cjm2671
cjm2671

Reputation: 19456

Transforming a collection to a map in Elixir

If I've got a collection of the form:

[{key, value}, {key, value2}, {key2, value3}]

how do I transform it to a map of the form

%{key => [value, value2], key2 => [value3]}

?

Upvotes: 1

Views: 50

Answers (1)

Aleksei Matiushkin
Aleksei Matiushkin

Reputation: 121000

Reducing with Map.update/4 would be a good fit:

[{:key, :value}, {:key, :value2}, {:key2, :value3}]
|> Enum.reduce(%{}, fn {k, v}, acc ->
  Map.update(acc, k, [v], fn l -> [v | l] end)
end)
#⇒ %{key: [:value2, :value], key2: [:value3]}

To preserve an order of lists, map to {k, Enum.reverse(n)} afterwards.

[{:key, :value}, {:key, :value2}, {:key2, :value3}]
|> Enum.reduce(%{}, fn {k, v}, acc ->
  Map.update(acc, k, [v], fn l -> [v | l] end)
end)
|> Enum.map(fn {k, v} -> {k, Enum.reverse(v)} end)
#⇒ %{key: [:value, :value2], key2: [:value3]}

Another option would be Enum.group_by/3

[{:key, :value}, {:key, :value2}, {:key2, :value3}]
|> Enum.group_by(&elem(&1, 0))
|> Enum.map(fn {k, v} -> {k, Keyword.values(v)} end)
|> Enum.into(%{})
#⇒ %{key: [:value, :value2], key2: [:value3]}

or, with a mapper:

[{:key, :value}, {:key, :value2}, {:key2, :value3}]
|> Enum.group_by(&elem(&1, 0), &elem(&1, 1)) 
#⇒ %{key: [:value, :value2], key2: [:value3]}

Upvotes: 2

Related Questions