按两个维度进行分组,并在Elixir中进行计数。

问题描述 投票:0回答:1

我是想用两个维度进行分组,然后统计每个类别子类别中每个元素的数量。

data = [
  %{brand: "Mercedes", color: "blue"},
  %{brand: "Mercedes", color: "blue"},
  %{brand: "BMW", color: "blue"},
  %{brand: "BMW", color: "blue"},
  %{brand: "BMW", color: "blue"},
  %{brand: "Lada", color: "blue"},
  %{brand: "Mercedes", color: "red"},
  %{brand: "Mercedes", color: "red"},
  %{brand: "Mercedes", color: "red"},
  %{brand: "Mercedes", color: "red"},
  %{brand: "BMW", color: "black"}
]

的预期结果。

[
  %{"Mercedes": ["blue": 2, "red": 4]},
  %{"Lada": ["blue": 1]},
  %{"BMW": ["blue": 3, "black": 1]}
]

从结果来看,我有一些接近的东西, 但它并不完全是我想要的。

per_brands = Enum.group_by(data, fn (item) -> [item[:brand]] end)
Enum.map(
  per_brands,
  fn (cars_per_brand) ->
    %{
      "#{elem(cars_per_brand, 0)}": (
        Enum.map(
          Enum.group_by(elem(cars_per_brand, 1), fn (car) -> car[:color] end),
          fn (cars_per_brands_per_colors) ->
            %{"#{elem(cars_per_brands_per_colors, 0)}": Enum.count(elem(cars_per_brands_per_colors, 1))}
          end
        ))
    }
  end
)

# Result: (not exactly what I want)
[
  %{BMW: [%{black: 1}, %{blue: 3}]},
  %{Lada: [%{blue: 1}]},
  %{Mercedes: [%{blue: 2}, %{red: 4}]}
]

我相信有一些更聪明更好的方法来处理 reduce/3但我无法理解。

elixir reduce
1个回答
1
投票

你可以用reduce这样做。

Enum.reduce(data, %{}, fn %{brand: brand, color: color}, acc ->
  colors = Map.get(acc, brand, %{}) |> Map.update(color, 1, &(&1 + 1))
  Map.put(acc, brand, colors)
end)

对于每一个品牌颜色对,建立一个地图的地图, 当发现颜色计数时就递增。

结果。

%{
  'BMW' => %{'black' => 1, 'blue' => 3},
  'Lada' => %{'blue' => 1},
  'Mercedes' => %{'blue' => 2, 'red' => 4}
}

0
投票

我做的事情比我最初的方法要好得多 Map.ReduceAccess.key/2 也是。

Enum.reduce(
  data,
  %{},
  fn (item, acc) ->
    new_value = if (acc[item[:brand]][item[:color]]) do
      # The value already exists
      acc[item[:brand]][item[:color]] + 1
    else
      # The value does not exist, initialize to 1
      1
    end

    acc = put_in(acc, [Access.key(item[:brand], %{}), item[:color]], new_value)
  end
)

我觉得@亚当的解决方案更整洁,虽然。

© www.soinside.com 2019 - 2024. All rights reserved.