如何“深度合并”字典?

fra*_*ans 7 python dictionary python-3.5

想象一下以下命令:

a = {'key1': {'subkey1': [1, 2, 3]}}
b = {'key1': {'subkey2': [1, 2, 3]}}
Run Code Online (Sandbox Code Playgroud)

我想合并它们以获得

c = {'key1': {'subkey1': [1, 2, 3],
              'subkey2': [1, 2, 3]}}
Run Code Online (Sandbox Code Playgroud)

额外好的解决方案是返回深层副本ab我可以在不更改a或的情况下进行更改b

c = {**a, **b}
Run Code Online (Sandbox Code Playgroud)

看起来不错,但似乎与我的情况c = copy(a).update(b)返回的结果相同,因为被更新覆盖。bkey1

您当然可以像这样手动执行此操作(在另一个答案中找到):

def combine_dict(map1: dict, map2: dict):
    def update(d: dict, u: dict):
        for k, v in u.items():
            if isinstance(v, collections.Mapping):
                r = update(d.get(k, {}), v)
                d[k] = r
            else:
                d[k] = u[k]
        return d
    _result = {}
    update(_result, map1)
    update(_result, map2)
    return _result
Run Code Online (Sandbox Code Playgroud)

但我们现在有了 Python 3.5 - 也许事情已经改变了?

rap*_*cke 2

您需要递归来完成此任务。幸运的是,GitHub 上的 milanboers让我们免于长时间的工作和可能造成的脑损伤。

def deep_merge(dict1: dict, dict2: dict) -> dict:
    """ Merges two dicts. If keys are conflicting, dict2 is preferred. """
    def _val(v1, v2):
        if isinstance(v1, dict) and isinstance(v2, dict):
            return deep_merge(v1, v2)
        return v2 or v1
    return {k: _val(dict1.get(k), dict2.get(k)) for k in dict1.keys() | dict2.keys()}


a = {'key1': {'subkey1': [1, 2, 3]}}
b = {'key1': {'subkey2': [1, 2, 3]}}

a = deep_merge(a, b)
print(a)
Run Code Online (Sandbox Code Playgroud)

结果是:

{'key1': {'subkey2': [1, 2, 3], 'subkey1': [1, 2, 3]}}
Run Code Online (Sandbox Code Playgroud)