Elixir:将具有相同地图键的列表合并到一个地图

时间:2017-10-01 23:02:06

标签: elixir

如何在elixir中转换此列表

[
%{key1: 1, key2: 2, key3: 3},
%{key1: 4, key2: 5, key3: 6},
%{key1: 7, key2: 8, key3: 9}
]

到这张地图

%{key1: [1, 4, 7], key2: [2, 5, 8], key3: [3, 6, 9])

3 个答案:

答案 0 :(得分:7)

你可以两次通过;第一个将所有内容展平为单个一维的键值对列表,然后按键将第二个通道分组。

input = [
  %{key1: 1, key2: 2, key3: 3},
  %{key1: 4, key2: 5, key3: 6},
  %{key1: 7, key2: 8, key3: 9}
]

input
|> Enum.flat_map(fn m -> Map.to_list(m) end) 
|> Enum.group_by(fn {k, _} -> k end, fn {_, v} -> v end) 

<强>输出

%{key1: [1, 4, 7], key2: [2, 5, 8], key3: [3, 6, 9]}

答案 1 :(得分:1)

Enum.reduce(input, %{key1: [], key2: [], key3: []}, fn m, acc ->
  Map.merge(acc, m, fn _k, v1, v2 -> v1 ++ [v2] end)
end)
#⇒ %{key1: [1, 4, 7], key2: [2, 5, 8], key3: [3, 6, 9]}

或者,没有预先硬编码的累加器:

Enum.reduce(input, %{}, fn m, acc ->
  Map.merge(acc, m, fn
    _k, v1, v2 when is_list(v1) ->
      :lists.reverse([v2 | :lists.reverse(v1)])
    _k, v1, v2 -> [v1, v2]
  end)
end)
#⇒ %{key1: [1, 4, 7], key2: [2, 5, 8], key3: [3, 6, 9]}

答案 2 :(得分:0)

Elixir还不是很好,但我已经想到了这个:

map = Enum.reduce(list, %{}, fn(inner_map, acc) ->
        Map.merge(acc, inner_map, fn(_, v1, v2) ->
          if is_list(v1) do
            v1 ++ [v2]
          else
            [v1] ++ [v2]
          end
        end)
      end)

但我认为必须有更优雅的方式来做到这一点