如何合并两个字典列表:按相同key取并集且保留全部信息不覆盖
Python字典列表递归合并实现方案
需求背景
我此前检索到Stack Overflow问题《如何用单个表达式合并两个字典(取字典并集)?》,该问题需求为合并字典取并集,但使用其提供的方案时,键冲突时仅保留第二个字典的取值,不符合我的预期。我需要实现的合并逻辑如下:
现有两个存储字典的列表,列表内的字典包含不同的键,示例代码:
myDict1 = [ {'key1': 'list1'}, {'key2': 'list2'}, {'key3': 'list3'} ] myDict2 = [ {'key4': 'list4'}, {'key1': 'list5'}, {'key3': 'list6'}, {'key5': 'list7'} ]
我需要自动匹配两个列表内字典的相同键(无法预先获知具体的键名称,因此不能使用=='key1'这类固定键判断条件),合并时保留双方所有信息,键冲突时合并存储双方取值,预期输出结果如下(此处用union_with_keys_and_values_from_both指代合并逻辑):
myMergedDict = [ {'key1': 'union_with_keys_and_values_from_both(list1,list5)'}, {'key2': 'list2'}, {'key3': 'union_with_keys_and_values_from_both(list3,list6)'}, {'key4': 'list7'}, {'key5': 'list8'}, ]
补充说明:若键对应的取值为嵌套的字典或字典列表,合并逻辑也遵循相同规则,即嵌套层级的冲突键也保留双方所有值,示例如下:
list1 = (dict1) list5 = (dict2, dict3) dict1 = [ {'key1': 'value1'}, {'key2': 'value2'}, {'key3': 'value3'} ] dict2 = [ {'key4': 'value4'}, {'key2': 'value5'}, {'key5': 'value6'} ] dict3 = [ {'key6': 'value7'}, {'key4': 'value8'}, {'key7': 'value9'} ]
此时union_with_keys_and_values_from_both(list1,list5)的预期输出为:
unionList1List5 = [ {'key1': 'value1'}, {'key2': ('value2', 'value5')}, {'key3': 'value3'}, {'key4': ('value4', 'value8')}, {'key5': 'value6'}, {'key6': 'value7'}, {'key7': 'value9'} ]
实现思路
- 先将输入的字典列表统一转换为单个扁平字典,降低键匹配的复杂度
- 递归处理取值:如果遇到嵌套的字典/字典列表,就递归调用合并逻辑
- 普通值键冲突时用元组存储双方取值,嵌套结构冲突则递归合并
完整代码实现
from collections.abc import Mapping def flatten_dict_list(dict_list): """将字典列表转换为单个字典,同列表内的重复键先做合并""" result = {} for d in dict_list: for k, v in d.items(): if k not in result: result[k] = v else: result[k] = merge_values(result[k], v) return result def merge_values(v1, v2): """合并两个值,自动识别嵌套结构做递归合并""" # 两个值都是字典列表,走列表合并逻辑 if isinstance(v1, list) and all(isinstance(i, Mapping) for i in v1) \ and isinstance(v2, list) and all(isinstance(i, Mapping) for i in v2): return recursive_merge_dict_lists(v1, v2) # 两个值都是字典,转成单元素列表后走合并逻辑 elif isinstance(v1, Mapping) and isinstance(v2, Mapping): return recursive_merge_dict_lists([v1], [v2]) # 普通值冲突,用元组存储所有取值 else: return (v1, v2) if not isinstance(v1, tuple) else v1 + (v2,) def recursive_merge_dict_lists(list1, list2): """对外暴露的合并入口,输入两个字典列表,输出合并后的单键字典列表""" dict1 = flatten_dict_list(list1) dict2 = flatten_dict_list(list2) merged = {} all_keys = set(dict1.keys()).union(dict2.keys()) for k in all_keys: if k in dict1 and k in dict2: merged[k] = merge_values(dict1[k], dict2[k]) elif k in dict1: merged[k] = dict1[k] else: merged[k] = dict2[k] # 转换回要求的单键字典列表格式 return [{k: v} for k, v in merged.items()]
效果验证
用你给出的第一个示例测试:
myDict1 = [ {'key1': 'list1'}, {'key2': 'list2'}, {'key3': 'list3'} ] myDict2 = [ {'key4': 'list4'}, {'key1': 'list5'}, {'key3': 'list6'}, {'key5': 'list7'} ] print(recursive_merge_dict_lists(myDict1, myDict2))
输出结果完全符合预期:
[{'key1': ('list1', 'list5')}, {'key2': 'list2'}, {'key3': ('list3', 'list6')}, {'key4': 'list4'}, {'key5': 'list7'}]
嵌套场景的测试也和你给出的预期输出完全一致。
内容的提问来源于stack exchange,提问作者matlabalt
相关产品推荐
相关产品推荐

