I have this map
%{
total: 38,
value: 22
}
And would like to add the key :ratio
. Is there a way to write immediately:
%{
total: 38,
value: 22,
ratio: __SELF__.value / __SELF__.total
}
or do I need to create another map to achieve this?
Thanks
All data is immutable, so you always have to make a new map.
A simple way, assuming your map is called map
:
iex> Map.put(map, :ratio, map.value / map.total)
%{ratio: 0.5789473684210527, total: 38, value: 22}
If you mean that you want to create the map before it already exists, then it would be better to put total
and value
into variables, and use them to build the map:
defmodule Example do
def make_map(total, value) do
%{total: total, value: value, ratio: value / total}
end
end
iex(1)> Example.make_map(38, 22)
%{ratio: 0.5789473684210527, total: 38, value: 22}
Makes sense. Since I really wanted to avoid assigning the temporary map to a variable nor build a function for this, I'll go for
%{value: 12, total: 18} |> (&(Map.put(&1, :ratio, &1.value / &1.total))).()
. Not very elegant I reckon thoughRepeating the numbers would probably be simpler:
%{value: 12, total: 18, ratio: 12/18}
Except of course the numbers are not static but come from an expensive SQL query.
Then your function works fine, but obviously I prefer mine. :) You can inline it like this:
map |> (fn %{value: v, total: t} -> %{value: v, total: t, ratio: v/t} end).()
Those numbers coming from the expensive SQL query aren't stored in variables in memory in any way? You've clearly got access to both total and value somehow... it doesn't make sense why you want to put them a self-referential structure and then retrieve them from the structure instead of just using them directly. Adam's answer is right.