我有不明数量的字典,其中包含一组未知的键,例如:
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'}}
This question听起来确实很接近我想要的声音,但结果却相同:
>>> {**d1, **d2, **d3, **d4}
{'job': {'metadata': {'date': 'string'}}, 'user': {'id': 'string'}}
这个问题专门要求建立工会,但对我来说,这看起来并不像工会。我想念什么?
答案 0 :(得分:1)
这是一种通用尝试,它使用recursion
,generator
和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'}
}
答案 1 :(得分:1)
您要在AFAIU中合并具有相似键的字典,并为不同键更新。
这是使用python 3.9的新语法的简单尝试:
def nested_union(a, b):
new_dict = a.copy()
for key, value in a.items():
if key not in b:
new_dict |= b # new_dict.update(b)
elif not isinstance(value, dict):
new_dict = a | b # {**a, **b}
else:
new_dict[key] = nested_union(value, b[key])
return new_dict
我建议您对提供的代码进行单元测试,因为我的测试基于您的示例。带有* args的扩展名将提高使用过程中的可读性。