How to merge list pares into a single Map?

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}
1 Like

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 |> [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.into combination creates an intermediate list, while the for-comprehension does not.


I could use Stream :wink:

1 Like

That would not resolve the problem, only delay it:

|> [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}.

|> [k, v] -> { String.to_existing_atom(k), v} end) 
|> Stream.into(%{}) 

would not do anything until 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:

|> Enum.into(%{}, fn [k, v] ->  { String.to_existing_atom(k), v} end)
1 Like

Why not use simply and Enum.into? :slight_smile: 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.

1 Like

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… ^.^

1 Like