Elixir 将地图列表转换为单个地图
像Elixir 将地图列表转换为单个地图,elixir,Elixir,像some_-maps=[%{“test”=>[1]}、%{“test2”=>[2]}、%{“test”=>[3]}]这样的映射列表如何转换为一个巨大的单一映射,并合并其值 single_map = %{"test" => [1, 3], "test2" => [2]} 因为我不能在像for这样的迭代中修改映射,所以我不知道如何构建这个映射 在另一种语言中,我会定义一个空映射并遍历列表并填充映射,但从功能上看,我不知道如何才能做到这一点。这里有一种方法: Enum.reduce(s
some_-maps=[%{“test”=>[1]}、%{“test2”=>[2]}、%{“test”=>[3]}]
这样的映射列表如何转换为一个巨大的单一映射,并合并其值
single_map = %{"test" => [1, 3], "test2" => [2]}
因为我不能在像for
这样的迭代中修改映射,所以我不知道如何构建这个映射
在另一种语言中,我会定义一个空映射并遍历列表并填充映射,但从功能上看,我不知道如何才能做到这一点。这里有一种方法:
Enum.reduce(some_maps, fn x, y ->
Map.merge(x, y, fn _k, v1, v2 -> v2 ++ v1 end)
end)
reduce解决方案无疑是产品质量的答案。但是,由于您提到了函数编程所遇到的困难,请考虑Real:的“长手”版本。
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分解为一个适当的函数,该函数更容易推理,也更容易用注释标记
根据你原来的问题:
在另一种语言中,我将定义一个空映射,遍历列表并填充映射
请注意,这是对上述
merge
和do\u merge
功能如何工作的合理描述。您并没有像您所认为的那样远离功能性思考。对于这些您想要迭代和更改某些内容的问题,答案总是Enum.reduce
:)枚举模块中的所有其他函数都是在其上实现的。我可以发布完整的答案,但我认为如果你尝试先解决Enum.reduce,你会学到更多。谢谢!我试过使用reduce,但不知道,我会继续尝试,很难用函数的方式来思考:P