如何创建嵌套 group_by?
How can I create nested group_by?
本质上,我正在尝试获取数据并使用 Enum.group_by 创建字典,但我想继续按子类别对相同数据进行分组。
data = [
%{company: "company_one", state: "LA", size: 100},
%{company: "company_one", state: "LA", size: 200},
%{company: "company_two", state: "TX", size: 200},
%{company: "company_two", state: "LA", size: 300},
%{company: "company_three", state: "LA", size: 400},
%{company: "company_four", state: "TX", size: 500}
]
我想先按公司分组,然后在地图中按州分组,然后再在嵌套地图中按大小分组。本质上是一个包含两个嵌套地图和一个相应数据数组的地图。
%{"company_one" => %{
"LA" => %{
"100" => [
%{company: company_one, state: LA, size: 100}
],
"200" => [
%{company: company_one, state: LA, size: 200}
]
}
}
}
我的尝试看起来像这样
list =
data
|> Enum.group_by(fn x -> x.company end)
keys = Map.keys(data)
updated_list =
for key <- keys do
list[key]
|> Enum.group_by(fn x -> x.state end)
end
我使用 Enum.group_by/1 作为初始格式,但之后我尝试过的任何东西都弄乱了数据结构。任何帮助都会很棒。谢谢
它不是很漂亮,但你可以这样做:
Enum.group_by(data, & &1.company)
|> Map.new(fn {k, v} ->
{k,
Enum.group_by(v, & &1.state)
|> Map.new(fn {k, v} -> {k, Enum.group_by(v, & &1.size)} end)}
end)
结果:
%{
"company_four" => %{
"TX" => %{500 => [%{company: "company_four", size: 500, state: "TX"}]}
},
"company_one" => %{
"LA" => %{
100 => [%{company: "company_one", size: 100, state: "LA"}],
200 => [%{company: "company_one", size: 200, state: "LA"}]
}
},
"company_three" => %{
"LA" => %{400 => [%{company: "company_three", size: 400, state: "LA"}]}
},
"company_two" => %{
"LA" => %{300 => [%{company: "company_two", size: 300, state: "LA"}]},
"TX" => %{200 => [%{company: "company_two", size: 200, state: "TX"}]}
}
}
我发现这个问题很有趣,并最终制定了一种通用的方法来执行此操作 - 只需传递您的结构和要分组的键。
defmodule NestedGroup do
defp access_keys([key]), do: [Access.key(key, [])]
defp access_keys([key | rest]), do: [Access.key(key, %{}) | access_keys(rest)]
def nested_group(data, keys) do
data
|> Enum.reduce(%{}, fn elt, acc ->
keys =
Enum.map(keys, &Map.get(elt, &1))
|> access_keys()
update_in(acc, keys, fn list -> [elt | list] end)
end)
end
end
我们需要 access_key
助手来确保最后一个键是列表,而不是映射。
iex(2)> NestedGroup.nested_group(data, [:company, :state, :size])
%{
"company_four" => %{
"TX" => %{500 => [%{company: "company_four", size: 500, state: "TX"}]}
},
"company_one" => %{
"LA" => %{
100 => [%{company: "company_one", size: 100, state: "LA"}],
200 => [%{company: "company_one", size: 200, state: "LA"}]
}
},
"company_three" => %{
"LA" => %{400 => [%{company: "company_three", size: 400, state: "LA"}]}
},
"company_two" => %{
"LA" => %{300 => [%{company: "company_two", size: 300, state: "LA"}]},
"TX" => %{200 => [%{company: "company_two", size: 200, state: "TX"}]}
}
}
本质上,我正在尝试获取数据并使用 Enum.group_by 创建字典,但我想继续按子类别对相同数据进行分组。
data = [
%{company: "company_one", state: "LA", size: 100},
%{company: "company_one", state: "LA", size: 200},
%{company: "company_two", state: "TX", size: 200},
%{company: "company_two", state: "LA", size: 300},
%{company: "company_three", state: "LA", size: 400},
%{company: "company_four", state: "TX", size: 500}
]
我想先按公司分组,然后在地图中按州分组,然后再在嵌套地图中按大小分组。本质上是一个包含两个嵌套地图和一个相应数据数组的地图。
%{"company_one" => %{
"LA" => %{
"100" => [
%{company: company_one, state: LA, size: 100}
],
"200" => [
%{company: company_one, state: LA, size: 200}
]
}
}
}
我的尝试看起来像这样
list =
data
|> Enum.group_by(fn x -> x.company end)
keys = Map.keys(data)
updated_list =
for key <- keys do
list[key]
|> Enum.group_by(fn x -> x.state end)
end
我使用 Enum.group_by/1 作为初始格式,但之后我尝试过的任何东西都弄乱了数据结构。任何帮助都会很棒。谢谢
它不是很漂亮,但你可以这样做:
Enum.group_by(data, & &1.company)
|> Map.new(fn {k, v} ->
{k,
Enum.group_by(v, & &1.state)
|> Map.new(fn {k, v} -> {k, Enum.group_by(v, & &1.size)} end)}
end)
结果:
%{
"company_four" => %{
"TX" => %{500 => [%{company: "company_four", size: 500, state: "TX"}]}
},
"company_one" => %{
"LA" => %{
100 => [%{company: "company_one", size: 100, state: "LA"}],
200 => [%{company: "company_one", size: 200, state: "LA"}]
}
},
"company_three" => %{
"LA" => %{400 => [%{company: "company_three", size: 400, state: "LA"}]}
},
"company_two" => %{
"LA" => %{300 => [%{company: "company_two", size: 300, state: "LA"}]},
"TX" => %{200 => [%{company: "company_two", size: 200, state: "TX"}]}
}
}
我发现这个问题很有趣,并最终制定了一种通用的方法来执行此操作 - 只需传递您的结构和要分组的键。
defmodule NestedGroup do
defp access_keys([key]), do: [Access.key(key, [])]
defp access_keys([key | rest]), do: [Access.key(key, %{}) | access_keys(rest)]
def nested_group(data, keys) do
data
|> Enum.reduce(%{}, fn elt, acc ->
keys =
Enum.map(keys, &Map.get(elt, &1))
|> access_keys()
update_in(acc, keys, fn list -> [elt | list] end)
end)
end
end
我们需要 access_key
助手来确保最后一个键是列表,而不是映射。
iex(2)> NestedGroup.nested_group(data, [:company, :state, :size])
%{
"company_four" => %{
"TX" => %{500 => [%{company: "company_four", size: 500, state: "TX"}]}
},
"company_one" => %{
"LA" => %{
100 => [%{company: "company_one", size: 100, state: "LA"}],
200 => [%{company: "company_one", size: 200, state: "LA"}]
}
},
"company_three" => %{
"LA" => %{400 => [%{company: "company_three", size: 400, state: "LA"}]}
},
"company_two" => %{
"LA" => %{300 => [%{company: "company_two", size: 300, state: "LA"}]},
"TX" => %{200 => [%{company: "company_two", size: 200, state: "TX"}]}
}
}