Nothing special here. You could use atoms for currency names, but that makes things more complicated when interacting with other systems.
all_currencies = ["AUD", "CVE", "USD"]
I’ve bolded the key words that suggest the data structure, a list of maps:
currencies = [
%{name: "USD", exchange_rate: 1.23, value: 0.87},
%{name: "CVE", exchange_rate: 1.75, value: 0.75},
%{name: "AUD", exchange_rate: 1.01, value: 0.99}
]
The numbers here are written as floats, but that may not be what you want. Consider the Decimal library for doing financial arithmetic.
“Record” could also be satisfied with a defstruct (or an Erlang record if you’re feeling exotic).
Looking up a record is spelled Enum.find(currencies, & &1.name == "USD"). If the code does this a lot, consider making a map out of currencies:
currencies_map = Map.new(currencies, fn v -> {v.name, v} end)
exchange_rates = %{
"AUD" => %{"USD" => 1.14, "CVN" => 1.2},
# OR, if an exchange rate is more complicated than just a number
"USD" => %{"CVN" => %{rate: 0.67, quote_id: 1234}, "AUD" => %{rate: 1.06, quote_id: 4567}}
}
The benefit of using nested maps here is that looking up an exchange rate is spelled exchange_rates[source_currency][destination_currency].
If there is more than one exchange rate for a given currency pair, this approach will not work. Consider using lists for that case.
exchanged_values =
exchange_rates
|> Map.new(fn {src_currency, dest_currencies} ->
{
src_currency,
Map.new(dest_currencies, fn {dest_currency, exchange_rate} ->
# do something with src_currency, dst_currency, and exchange_rate
# probably look things up in currencies
result = %{
name: dst_currency, # or "#{src_currency} -> #{dst_currency}"
exchange_rate: ... # calculate this
value: ... # and this
}
{dest_currency, result}
end
}
end
This results in a new map of maps; exchanged_values[source_currency][dest_currency] is a map just like the ones in currencies.
That last part about adding initial and final values to the same list seems tricky; how do consumers of R know how to interpret the {name: ..., exchange_rate:..., value:...} results?
One option would be to have R contain tuples:
exchanged_values
|> Enum.flat_map(fn {src_currency, dest_currencies} ->
dest_currencies
|> Enum.map(fn {dest_currency, final_value} ->
# get initial_value for dest_currency from currencies
{initial_value, final_value}
end)
|> Enum.filter(fn {initial_value, final_value} ->
# decide if record should be included or not
end)
end)
This uses Enum.flat_map for two reasons:
- we’re building a list, but a single key of the input may return many values
- some keys in the input may return NO values






















