I have a list like this.
[ ["key1", 1], ["key2", 2], ["key3", 3] ]
Is there any way to convert the list into a single map like this?
%{key1: 1, key2: 2, key3: 3}
I have a list like this.
[ ["key1", 1], ["key2", 2], ["key3", 3] ]
Is there any way to convert the list into a single map like this?
%{key1: 1, key2: 2, key3: 3}
A for comprehension works nicely here:
list = [ ["key1", 1], ["key2", 2], ["key3", 3] ]
for [k, v] <- list, into: %{}, do: { String.to_atom(k), v }
And also âclassicâ approach:
list |> Stream.map(fn [k, v] -> { String.to_atom(k), v} end) |> Enum.into(%{})
In this case comprehension is awesome, because itâs really concise and readable.
Depending of the source of the strings, Iâd prefer to use String.to_existing_atom/1
to not waste strictly limited ressources.
Thank you for the quick replies!
I can convert it as I expected!
BTW, as the list was filtered with Enum.filter/2 beforehand, I donât have to worry to waste the Atom tables, in fact.
An important difference between the solutions that @amarraja and @PatNowak presented, is that the Enum.map + Enum.into combination creates an intermediate list, while the for-comprehension does not.
I could use Stream
That would not resolve the problem, only delay it:
list_of_kv_lists
|> Enum.map(fn [k, v] -> { String.to_existing_atom(k), v} end)
|> Enum.into(%{})
would first transform
[ ["key1", 1], ["key2", 2], ["key3", 3] ]
into
[ {:key1, 1}, {:key2, 2}, {:key3, 3}]
and this then into
%{key1: 1, key2: 2, key3: 3}
.
list_of_kv_lists
|> Stream.map(fn [k, v] -> { String.to_existing_atom(k), v} end)
|> Stream.into(%{})
|> Stream.run
would not do anything until Stream.run
is reached, and then take the first element [âkey1â, 1], transform it into {:key1, 1}, insert this into the map, take the second element [âkey2â, 2], transform it into {:key2, 2}, insert this into the map, etc.
This transformation step thus still is done separately.
If you want to do it âat onceâ, you can either use a for-comprehension or use the three-argument version of Enum.into
:
list_of_kv_lists
|> Enum.into(%{}, fn [k, v] -> { String.to_existing_atom(k), v} end)
Why not use simply Stream.map
and Enum.into
? I updated my answer above.
Because this would mean that you add the extra overhead of working with Streams for no extra purpose. If you want to be sure you can benchmark, but I am fairly certain that in this simple example, the version that does not use streams is significantly faster.
This would be the âclassicâ approach Iâd use. ^.^
iex> list = [ ["key1", 1], ["key2", 2], ["key3", 3] ]
[["key1", 1], ["key2", 2], ["key3", 3]]
iex> list |> Enum.reduce(%{}, fn ([k,v],acc) -> Map.put(acc,String.to_existing_atom(k),v) end) %{key1: 1, key2: 2, key3: 3}
And no intermediate list, no stream overhead, etc⊠^.^