如何用map/zip/functools实现字典列表的列表求和且无需显式迭代?
问题描述
我有一个字典列表,每个字典的值都是四元素列表:
my_dict=[ { 'prop1': [1, 2, 3, 4], 'prop2': [1, 1, 0, 0] }, { 'prop1': [2, 3, 3, 1], 'prop3': [1, 1, 0, 0] } ]
希望不编写显式两层迭代,完成对应key的列表元素级求和,最终得到:
my_dict_sum={ 'prop1': [3, 5, 6, 5], 'prop2': [1, 1, 0, 0], 'prop3': [1, 1, 0, 0] }
更新:我已经实现了功能,但想改用map、zip或functools简化代码,去掉显式两层循环,当前实现代码如下:
my_dict_sum = {} for val in my_dict: for key, counts in val.items(): if key in my_dict_sum: my_dict_sum[key] = list(map(lambda x,y: x+y, my_dict_sum[key], counts)) else: my_dict_sum[key] = counts
解决方案
以下几种方法都能避免显式两层迭代,利用你提到的工具实现需求:
方法1:functools.reduce + collections.defaultdict
用reduce迭代合并字典,defaultdict简化初始key判断,map做元素级求和:
from functools import reduce from collections import defaultdict def merge_two_dicts(a, b): for key, vals in b.items(): a[key] = list(map(lambda x, y: x + y, a[key], vals)) if key in a else vals return a my_dict_sum = reduce(merge_two_dicts, my_dict, defaultdict(list)) # 可选:转换为普通字典 my_dict_sum = dict(my_dict_sum)
方法2:zip + map批量处理同key列表
先收集所有同key的列表,再用zip打包对应位置元素,map(sum)批量求和:
from collections import defaultdict # 收集每个key对应的所有列表 key_groups = defaultdict(list) for d in my_dict: for k, v in d.items(): key_groups[k].append(v) # 元素级求和:zip(*groups)把每个子列表的对应位置元素打包,sum对每组求和 my_dict_sum = {k: list(map(sum, zip(*groups))) for k, groups in key_groups.items()}
这个方法完全去掉了元素级的显式循环,是最简洁的实现之一。
方法3:简化版reduce字典推导式
把合并逻辑压缩到reduce的lambda中,适合场景简单的情况:
from functools import reduce my_dict_sum = reduce( lambda current, new: { k: list(map(lambda x,y: x+y, current[k], new[k])) if k in current and k in new else current.get(k, new.get(k)) for k in set(current.keys()).union(new.keys()) }, my_dict )
内容的提问来源于stack exchange,提问作者rfg
相关产品推荐
相关产品推荐

