如何将两个Elixir Map列表合并为以id为键的单Map
Elixir:合并两个Map列表的简便实现
输入的Map列表
list_one = [ %{id: :a, value: 1}, %{id: :b, value: 2}, %{id: :c, value: 3} ] list_two = [ %{id: :a, value: 1}, %{id: :b, value: 4}, %{id: :d, value: 5} ]
已知条件
- 每个列表内的
id唯一 id始终为原子类型,value始终为整数类型- 两个列表可能存在相同的
id - 每个列表可能包含对方没有的
id - 所有Map的键数量固定
合并需求
将两个列表合并为一个单Map:
- 以内部Map的
id作为顶层Map的键 - 对应值需包含两个列表的
value,若某列表无对应id则用0填充(该规则可选)
期望输出
%{ a: %{ value_one: 1, value_two: 1 }, b: %{ value_one: 2, value_two: 4 }, c: %{ value_one: 3, value_two: 0 }, d: %{ value_one: 0, value_two: 5 } }
诉求
已知可通过多次Enum.reduce实现,但想寻求更简便的方法。
解决方案
方法一:高效转换法(推荐)
先将两个列表转换为以id为键的Map,再收集所有id生成结果:
# 把列表转成 id => value 的Map map_one = Enum.into(list_one, %{}, fn %{id: id, value: val} -> {id, val} end) map_two = Enum.into(list_two, %{}, fn %{id: id, value: val} -> {id, val} end) # 获取所有唯一的id all_ids = Map.keys(map_one) ++ Map.keys(map_two) |> Enum.uniq() # 生成最终结果 result = Enum.into(all_ids, %{}, fn id -> {id, %{ value_one: Map.get(map_one, id, 0), value_two: Map.get(map_two, id, 0) }} end)
方法二:管道链式写法
通过合并列表、分组后处理,代码更简洁:
result = Enum.concat(list_one, list_two) |> Enum.group_by(& &1.id) |> Map.new(fn {id, entries} -> # 从分组中分别提取两个列表的value,无则用0填充 value_one = entries |> Enum.find_value(0, fn e -> e in list_one && e.value end) value_two = entries |> Enum.find_value(0, fn e -> e in list_two && e.value end) {id, %{value_one: value_one, value_two: value_two}} end)
注:方法二的
e in list_one是线性查找,若列表数据量较大,推荐使用方法一以保证效率。
内容的提问来源于stack exchange,提问作者Agos
相关产品推荐
相关产品推荐

