С такими данными, как:
data = %{
"Almond Fudge" => [
%{date: "2019-01-01", quantity: 1},
%{date: "2019-01-02", quantity: 1},
%{date: "2019-01-04", quantity: 3},
%{date: "2019-01-05", quantity: 5}
],
"Banana Split" => [
%{date: "2019-01-02", quantity: 3},
%{date: "2019-01-02", quantity: 5},
%{date: "2019-01-02", quantity: 3},
%{date: "2019-01-02", quantity: 5}
]
}
Вы можете сделать что-то вроде этого:
Enum.map(data, fn {product, sales} ->
{
product,
Enum.group_by(sales, &(String.slice(&1.date, 0, 7)), &(&1.quantity))
|> Enum.map(fn {k, v} ->
{k, Enum.sum(v)}
end) |> Map.new()
}
end) |> Map.new()
Эта строка: Enum.group_by(sales, &(&1.date), &(&1.quantity))
создаст карты с датами в качестве ключей и спискомзначений в качестве значений.
И затем вы можете преобразовать это в карту с датой в качестве ключей и общей суммой в виде значений, в которые она будет добавлена: Enum.map(fn {k, v} -> {k, Enum.sum(v)} end) |> Map.new()
И окончательный результат будет:
%{"Almond Fudge" => %{"2019-01" => 10}, "Banana Split" => %{"2019-01" => 16}}
Или, если вы хотите получить точный результат, если вы не хотите указывать даты в качестве ключей, вы можете заменить эту строку на: |> Enum.map(fn {k, v} -> %{date: k, quantity: Enum.sum(v)} end)}
Оставив вам:
Enum.map(data, fn {product, sales} ->
{
product,
Enum.group_by(sales, &(String.slice(&1.date, 0, 7)), &(&1.quantity))
|> Enum.map(fn {k, v} -> %{date: k, quantity: Enum.sum(v)} end)}
end) |> Map.new()
В результате:
%{
"Almond Fudge" => [%{date: "2019-01", quantity: 10}],
"Banana Split" => [%{date: "2019-01", quantity: 16}]
}
Спасибо @zwippie за указание на String.slice. Я не поняла, что ты спрашиваешь месяц. String.slice/3
примет строку, начальную позицию и длину. Таким образом, нарезка строки даты от 0 до 7 цифр приведет к появлению строк с указанием года и месяца.