首页 > 解决方案 > 合并多个嵌套字典

问题描述

我有未知数量的字典和一组未知的键,例如:

d1 = {'job': {'data': {'id': 'string'}}}
d2 = {'job': {'data': {'title': 'string'}}}
d3 = {'job': {'metadata': {'date': 'string'}}}
d4 = {'user': {'id': 'string'}}

我想要一个看起来像这样的组合字典:

{
    'job': {
        'data': {
            'id': 'string',
            'title': 'string'
        }
        'metadata': {
            'date': 'string'
        }
    },
    'user': {
        'id': 'string'
    }
}

内置的update并没有给我想要的东西:

>>> combined = {}
>>> combined.update(d1)
>>> combined.update(d2)
>>> combined.update(d3)
>>> combined.update(d4)
>>> combined
{'job': {'metadata': {'date': 'string'}}, 'user': {'id': 'string'}}

这个问题听起来很接近我想要的,但结果是一样的:

>>> {**d1, **d2, **d3, **d4}
{'job': {'metadata': {'date': 'string'}}, 'user': {'id': 'string'}}

这个问题特别要求工会,但在我看来,这不像是工会。我错过了什么?

标签: pythonpython-3.xdictionarymerge

解决方案


recursion这是一个通用尝试,它使用 a 、 agenerator和来回答您的问题reduce

from functools import reduce


def union_nested_dicts(a, b):
    a_keys = list(a.keys()) if isinstance(a, dict) else []
    b_keys = list(b.keys()) if isinstance(b, dict) else []
    for k in set(a_keys + b_keys):
        if not isinstance(a.get(k, {}), dict) or not isinstance(b.get(k, {}), dict):
            if a:
                # Or: yield from a.items()
                yield k, a.get(k, {})
            if b:
                yield from b.items()
        else:
            tmp = dict(union_nested_dicts(a.get(k, {}), b.get(k, {}))) 
            yield k, tmp


a = {'job': {'data': {'id': 'string'}}}
b = {'job': {'data': {'title': 'string'}}}
d3 = {'job': {'metadata': {'date': 'string'}}}
d4 = {'user': {'id': 'string'}}
out = reduce(
    lambda left, right: dict(union_nested_dicts(left, right)),
    [a, b, d3, d4]
)
print(out)

输出:

{
    'job': {
         'data': {'id': 'string', 'title': 'string'},
         'metadata': {'date': 'string'}
     },
     'user': {'id': 'string'}
}

推荐阅读