我有一份待办事项清单:
[
{%{date_value: ~D[2017-01-01], weekday: 7}, %{todo: "a", priority: 1}},
{%{date_value: ~D[2017-01-01], weekday: 7}, %{todo: "b", priority: 2}},
{%{date_value: ~D[2017-01-01], weekday: 7}, %{todo: "c", priority: 3}},
{%{date_value: ~D[2017-01-02], weekday: 1}, nil},
{%{date_value: ~D[2017-01-03], weekday: 2}, %{todo: "d", priority: 2}},
]
但我需要一个这样的清单:
[
%{date_value: ~D[2017-01-01], weekday: 7, tasks: [%{todo: "a", priority: 1},
%{todo: "b", priority: 2},
%{todo: "c", priority: 3}]},
%{date_value: ~D[2017-01-02], weekday: 1, tasks: []},
%{date_value: ~D[2017-01-03], weekday: 2, tasks: [%{todo: "d", priority: 2}]}
]
如何将第一个版本转换为第二个版本?
我理解[head | tail]
是一种递归遍历此列表以编译新列表的方法。但我不明白如何从这一次递归中收集所有todo
以便将它们组合到自己的列表中。
答案 0 :(得分:3)
首先,按日期组件对列表进行分组,值函数仅返回任务。这将创建从日期组件到任务列表的Map。然后,将地图转换回列表,在此过程中还会移除nil
值,因为您根据示例输出不需要它们。
list = [
{%{date_value: ~D[2017-01-01], weekday: 7}, %{todo: "a", priority: 1}},
{%{date_value: ~D[2017-01-01], weekday: 7}, %{todo: "b", priority: 2}},
{%{date_value: ~D[2017-01-01], weekday: 7}, %{todo: "c", priority: 3}},
{%{date_value: ~D[2017-01-02], weekday: 1}, nil},
{%{date_value: ~D[2017-01-03], weekday: 2}, %{todo: "d", priority: 2}},
]
list
|> Enum.group_by(fn {date, _} -> date end, fn {_, task} -> task end)
|> Enum.map(fn {date, tasks} ->
date |> Map.put(:tasks, Enum.filter(tasks, &(&1)))
end)
|> IO.inspect
输出:
[%{date_value: ~D[2017-01-01],
tasks: [%{priority: 1, todo: "a"}, %{priority: 2, todo: "b"},
%{priority: 3, todo: "c"}], weekday: 7},
%{date_value: ~D[2017-01-02], tasks: [], weekday: 1},
%{date_value: ~D[2017-01-03], tasks: [%{priority: 2, todo: "d"}], weekday: 2}]
(地图是无序的,因此此输出与预期输出相同。)