将地图列表转换为单个地图

时间:2018-01-22 09:25:09

标签: elixir

如何将some_maps = [%{"test" => [1]}, %{"test2" => [2]}, %{"test" => [3]}]这样的地图列表转换为一个巨大的单一地图,并将其值合并?

single_map = %{"test" => [1, 3], "test2" => [2]}

由于我无法在for之类的迭代中修改地图,所以我不知道如何构建此地图

在其他语言中,我会定义一个空地图并遍历列表并填充地图,但在功能上我认为我不知道如何做到这一点。

2 个答案:

答案 0 :(得分:3)

这是一种方法:

Enum.reduce(some_maps, fn x, y ->
   Map.merge(x, y, fn _k, v1, v2 -> v2 ++ v1 end)
end)

答案 1 :(得分:2)

reduce解决方案绝对是生产质量的答案。但是,既然您提到了函数式编程的难点,请考虑reduce的“long-hand”版本:

defmodule MapMerger do
  # The api function takes a list of maps, and returns them merged together.
  def merge(list_of_maps) do
    # This is written with a second function to hopefully be easier to follow;
    # these two functions could be collapsed using a default parameter
    # for the accumulator.
    do_merge(list_of_maps, %{})
  end

  # This is the base case, which will match after all maps have been processed
  # and the list is empty:
  defp do_merge([], acc), do: acc

  # Next comes the actual iterator; we pull head (the first item in the list),
  # process it, then recurse on the rest of the list and an updated accumulator
  defp do_merge([head|rest], acc) do
    updated_acc = Map.merge(acc, head)
    do_merge(rest, updated_acc)
  end
end

一旦你可以遵循这个,减少应该更容易思考 - 它不会修改任何东西,它只是不断地使用恰好是旧参数的更新版本的新参数。我的生产代码通常使用reduce来完成这样的小工作,但是当reduce中的操作很复杂时,我通常会将reduce分解为一个更容易推理的正确函数,并且更容易用注释标记。

从原来的问题:

  

在其他语言中,我会定义一个空地图并遍历列表并填充地图

请注意,这是对mergedo_merge函数如何工作的合理描述。你并不像你所认为的那样在功能上思考。