所以我有这张地图
map = [
%{id: 2, brand: "TUTU", reference: "1234"},
%{id: 2, brand: "TUTU", reference: "4567"},
%{id: 3, brand: "TOTO", reference: "789456"}
]
我想按ID将其分组以获得类似这样的内容:
[
%{
id: 2,
brand: "TUTU",
reference: [
"1234",
"5845"
]
},
%{
id: 3,
brand: "TOTO",
reference: [
"4587"
]
}
]
我试图这样使用Enum.group_by
map
|> Enum.group_by(fn entry -> entry.brand end)
但是结果看起来像这样:
%{
"TOTO" => [%{brand: "TOTO", id: 3, reference: "789456"}],
"TUTU" => [
%{brand: "TUTU", id: 2, reference: "1234"},
%{brand: "TUTU", id: 2, reference: "4567"}
]
}
我觉得我已经接近解决方案了,但是我不知道如何将信息重新分组到列表中,而不是使用键作为索引。...
抱歉,我不太清楚,我只是不知道如何描述我的问题
答案 0 :(得分:5)
另一种可能性是使用Enum.reduce/3
直接Kernel.update_in/3
进入所需的结构:
data
|> Enum.reduce(%{}, fn %{id: id, brand: brand, reference: ref}, acc ->
update_in(acc, [{id, brand}], fn
nil -> %{id: id, brand: brand, reference: [ref]}
refs -> %{refs | reference: [ref | refs.reference]}
end)
end)
|> Map.values()
答案 1 :(得分:2)
如果您不需要花太多时间来检测不需要分组的键,并且可以将它们列出在最前面,那么像这样的嵌套Enum.map
可以满足您的需求:
data = [
%{id: 2, brand: "TUTU", reference: "1234"},
%{id: 2, brand: "TUTU", reference: "4567"},
%{id: 2, brand: "TOTO", reference: "4567"},
%{id: 3, brand: "TOTO", reference: "789456"}
]
keys_to_group_by = [:id, :brand]
keys_to_list = [:reference]
data
|> Enum.group_by(&Map.take(&1, keys_to_group_by))
|> Enum.map(fn {key, values} ->
keys_to_list
|> Enum.map(fn key_to_list ->
{key_to_list, Enum.map(values, & &1[key_to_list])}
end)
|> Enum.into(key)
end)
请注意|> Enum.group_by(&Map.take(&1, keys_to_group_by))
-这是按许多键进行分组的部分,因此%{id: 2, brand: "TOTO"}
和%{id: 2, brand: "TUTU"}
最终位于不同的存储桶中。
答案 2 :(得分:1)
您还可以查看Enum.reduce/3和Map.update/4而不是简单的Enum.group_by/2
,以免您不必将已分组的条目映射到仅引用中。
map
|> Enum.reduce(%{}, &group_by_brand/2)
|> Enum.map(&to_map/1)
...
defp group_by_brand(entry, acc) do
Map.update(acc, {entry.id, entry.brand}, [entry.reference], &[entry.reference | &1])
end
defp to_map({{id, brand}, references}) do
%{id: id, brand: brand, references: references}
end