Python:如何按'id'与'size'对比并合并不同字典列表?
字典列表按指定键合并优化方案
我有两个字典列表(lod),需要按id和size键判断是否为相似项:
- 若相似,合并两个列表中的对应字典
- 若不相似,为第一个列表中的对应字典添加
count键并设默认值0
示例输入
lod1 = [{'id':1, 'size':1, 'colour':'a'}, {'id':1, 'size':2, 'colour':'ab'}, {'id':2, 'size':1, 'colour':'ab'}, {'id':2, 'size':2, 'colour':'ab'}] lod2 = [{'id':1, 'size':1, 'count':1}, {'id':1, 'size':2, 'count':2}, {'id':2, 'size':1, 'count':3}]
期望输出
merged = [{'id':1, 'size':1, 'colour':'a', 'count': 1}, {'id':1, 'size':2, 'colour':'ab', 'count': 2}, {'id':2, 'size':1, 'colour':'ab', 'count':3}, {'id':2, 'size':2, 'colour':'ab', 'count': 0}]
现有实现
我自己写了一个实现,但代码繁琐不够优雅。我用过defaultdict,也了解DeepDiff库,但不知道怎么在这个场景里应用。我的代码如下:
def merge(l1, l2): lod1_pairs = [(i['id'], i['size']) for i in l1] lod2_pairs = [(i['id'], i['size']) for i in l2] mismatched = [pair for pair in lod1_pairs if pair not in lod2_pairs] # 获取lod1中独有的键值对,为'count'设置默认值 merged = [] for i in lod1: if (i['id'], i['size']) in mismatched: # 为不匹配项添加'count'默认值 temp_dict = i| {'count': 0} merged.append(temp_dict) else: for j in lod2: # 直接对比键值 if i['id'] == j['id'] and i['size'] == j['size']: temp_dict = i | j # 合并字典 merged.append(temp_dict) return merged lod1 = [{'id':1, 'size':1, 'colour':'a'}, {'id':1 , 'size':2, 'colour':'ab'}, {'id':2, 'size':1, 'colour':'ab'}, {'id':2, 'size':2, 'colour':'ab'}] lod2 = [{'id':1, 'size':1, 'count':1}, {'id':1, 'size':2, 'count':2}, {'id':2, 'size':1, 'count':3}] merged = merge(lod1,lod2)
优化方案
核心思路
你的代码嵌套循环会导致时间复杂度达到O(n*m),可以先把lod2转换成以(id, size)为键的字典,将查找操作降为O(1),整体复杂度优化到O(n+m),代码也更简洁。这个场景不需要用到DeepDiff,普通字典就能搞定。
优化后的代码
def merge_lod(lod1, lod2): # 将lod2转换为(id, size)为键的映射字典,快速查找匹配项 lod2_map = {(item['id'], item['size']): item for item in lod2} merged = [] for item in lod1: key = (item['id'], item['size']) # 获取匹配项,无匹配时用默认的{'count':0},合并字典 merged_item = {**item, **lod2_map.get(key, {'count': 0})} merged.append(merged_item) return merged # 测试 lod1 = [{'id':1, 'size':1, 'colour':'a'}, {'id':1, 'size':2, 'colour':'ab'}, {'id':2, 'size':1, 'colour':'ab'}, {'id':2, 'size':2, 'colour':'ab'}] lod2 = [{'id':1, 'size':1, 'count':1}, {'id':1, 'size':2, 'count':2}, {'id':2, 'size':1, 'count':3}] merged = merge_lod(lod1, lod2) print(merged)
代码说明
- 构建映射字典:
lod2_map把lod2中的每个字典用(id, size)作为唯一标识存储,后续查找对应项无需循环遍历。 - 合并逻辑:遍历
lod1的每个字典,用lod2_map.get(key, {'count':0})获取匹配项,无匹配时返回默认值,再通过字典解包{**item, **...}合并两个字典(lod2仅含count键,不会和lod1的键冲突)。 - 顺序保持:结果列表的顺序和
lod1完全一致,符合需求。
至于defaultdict,它更适合批量设置默认值的场景,这里用普通字典的get方法已经足够简洁,无需额外引入。
内容的提问来源于stack exchange,提问作者Sharmat
相关产品推荐
相关产品推荐

