You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何合并两个字典列表:按相同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'}
]

实现思路

  1. 先将输入的字典列表统一转换为单个扁平字典,降低键匹配的复杂度
  2. 递归处理取值:如果遇到嵌套的字典/字典列表,就递归调用合并逻辑
  3. 普通值键冲突时用元组存储双方取值,嵌套结构冲突则递归合并

完整代码实现

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.14 09:27:00