【问题标题】:Convert list of maps into one single map将地图列表转换为一张地图
【发布时间】:2018-01-22 20:00:05
【问题描述】:

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

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

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

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

【问题讨论】:

  • 对于这些您想要迭代和更改某些内容的问题,答案始终是Enum.reduce。 :) Enum 模块中的所有其他功能都是在它之上实现的。我可以发布完整的答案,但我认为如果你尝试先解决它 Enum.reduce,你会学到更多。
  • 谢谢!我正在尝试减少但无法弄清楚,我会继续尝试,很难以功能方式思考:P

标签: elixir


【解决方案1】:

这是一种方法:

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

【讨论】:

    【解决方案2】:

    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
    

    一旦你可以遵循这一点,reduce 应该更容易考虑——它不会修改任何东西,它只是不断地递归使用恰好是旧参数的更新版本的新参数。我的生产代码一般用reduce做这样的小工作,但是当reduce里面的操作比较复杂的时候,我一般会把reduce分解成一个更容易推理,更容易用cmets标记的合适的函数。

    从你原来的问题:

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

    请注意,这是对上述mergedo_merge 函数如何工作的合理描述。您离功能性思考并没有您想象的那么远。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-07-06
      • 1970-01-01
      • 2022-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-01
      • 1970-01-01
      相关资源
      最近更新 更多