将地图列表转换为一张地图

lap*_*ira 1 elixir

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

single_map = %{"test" => [1, 3], "test2" => [2]}
Run Code Online (Sandbox Code Playgroud)

由于我无法在迭代中修改地图,就像for我不知道如何构建该地图

用其他语言,我将定义一个空的地图并遍历列表并填充该地图,但从功能上来说,我认为我看不到该怎么做。

hel*_*s35 5

这是一种实现方法:

Enum.reduce(some_maps, fn x, y ->
   Map.merge(x, y, fn _k, v1, v2 -> v2 ++ v1 end)
end)
Run Code Online (Sandbox Code Playgroud)


Chr*_*yer 5

reduce 解决方案绝对是生产质量的答案。但是,由于您提到了函数式编程的困难,请考虑 reduce 的“长期”版本:

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
Run Code Online (Sandbox Code Playgroud)

一旦你能遵循这一点,reduce 应该更容易思考——它不会修改任何东西,它只是不断地递归新参数,这些新参数恰好是旧参数的更新版本。我的生产代码通常reduce用于这样的小工作,但是当reduce内部的操作很复杂时,我通常会将reduce分解为一个更容易推理、更容易用注释标记的适当函数。

从你原来的问题:

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

请注意,这是对上述mergedo_merge函数如何工作的合理描述。你并没有像你相信的那样远离功能性思考。