鉴于此数据结构:
[
%{ collection: [ %{ description: "Foo", score: 4 }, %{ description: "Bar", score: 5 } ] },
%{ collection: [ %{ description: "Baz", score: 3 }, %{ description: "Foo", score: 4 } ] },
%{ collection: [ %{ description: "Bar", score: 1 }, %{ description: "Baz", score: 1 } ] }
]
我想为每个唯一description
创建一组新地图,并汇总相应的分数。像这样:
[
%{ description: "Foo", score: 8 },
%{ description: "Bar", score: 6 },
%{ description: "Baz", score: 4 }
]
可以将其分解为以下内容:
description
我想这个过程将涉及reduce
和map
的组合,但我所挣扎的是运行求和函数所必需的初始分组。一个惯用的灵药解决方案将是伟大的。谢谢!
答案 0 :(得分:2)
我会使用Enum.flat_map/2
和Enum.group_by/2
:
list = [
%{ collection: [ %{ description: "Foo", score: 4 }, %{ description: "Bar", score: 5 } ] },
%{ collection: [ %{ description: "Baz", score: 3 }, %{ description: "Foo", score: 4 } ] },
%{ collection: [ %{ description: "Bar", score: 1 }, %{ description: "Baz", score: 1 } ] }
]
list
|> Enum.flat_map(fn x -> x.collection end)
|> Enum.group_by(fn x -> x.description end)
|> Enum.map(fn {key, value} ->
%{description: key, score: value |> Enum.map(fn x -> x.score end) |> Enum.sum}
end)
|> IO.inspect
输出:
[%{description: "Bar", score: 6}, %{description: "Baz", score: 4},
%{description: "Foo", score: 8}]
请注意,由于group_by
使用了Map
,因此不会保留结果列表中的项目顺序。
答案 1 :(得分:1)
这个怎么样:
defmodule Group do
@groups [
%{ collection: [ %{ description: "Foo", score: 4 }, %{ description: "Bar", score: 5 } ] },
%{ collection: [ %{ description: "Baz", score: 3 }, %{ description: "Foo", score: 4 } ] },
%{ collection: [ %{ description: "Bar", score: 1 }, %{ description: "Baz", score: 1 } ] }
]
def transform(groups \\ @groups) do
groups
|> Enum.reduce([], fn group, list -> list ++ group[:collection] end)
|> Enum.group_by(&(&1.description), &(&1.score))
|> Enum.map(fn {key, v} -> {key, Enum.sum(v)} end)
|> Enum.into(%{})
end
end
iex(24)> Group.transform
%{"Bar" => 6, "Baz" => 4, "Foo" => 8}
答案 2 :(得分:0)
另一种方式:
Enum.reduce(collections, %{}, fn(%{collection: list}, acc) ->
Map.merge(acc, Enum.reduce(list, %{}, fn(map, acc2) -> Map.put(acc2, map[:description], map) end), fn(_k, v1, v2) ->
Map.put(v1, :score, v1[:score] + v2[:score])
end)
end)
|> Map.values()
最后一行|> Map.values()
对我来说是可选的。我删除了这一行,这样你就拥有了一个独特的密钥和一个对我来说更好的地图。