Reputation: 5460
I have two dictionaries that may be formatted like the following:
d1 = { "root" : { "leaf" : [diff1, diff2] }}
d2 = { "root" : { "leaf": [diff3], "node": { "leaf" : [diff1] } } }
I would like to be able to combine them into such a result:
d3 = {'root': {'leaf': ['diff1', 'diff2', 'diff 3'], 'node': {'leaf': ['diff 1']}}}
The level of recursion is undefined for any given input, but every "leaf node" will be an array, which I would like to combine if one exists for a leaf node in each dictionary. NOTE: The keys are not actually "node" and "leaf", i simply used these keys to help illustrate the example.
This code seems to completely overwrite my arrays with the second one:
d3 = {**d1, **d2}
yielding
result = {'root': {'leaf': ['diff 3'], 'node': {'leaf': ['diff 1']}}}
Upvotes: 0
Views: 54
Reputation: 3775
You can do this with a recursive function. Note this will only merge lists, not tuples or any other kind of sequence:
def merge_dicts(d1, d2):
out_dict = {}
for key in (set(d1.keys()) | set(d2.keys())):
if key in d1 and key in d2:
if isinstance(d1[key], dict) and isinstance(d2[key], dict):
out_dict[key] = merge_dicts(d1[key], d2[key])
elif isinstance(d1[key], list) and isinstance(d2[key], list):
out_dict[key] = d1[key] + d2[key]
elif d1[key] == d2[key]:
out_dict[key] = d1[key]
else:
raise ValueError(
'Cannot merge conflicting values {} and {}'.format(
d1[key], d2[key]))
elif key in d1:
out_dict[key] = d1[key]
else:
out_dict[key] = d2[key]
return out_dict
d1 = { "root" : { "leaf" : ['diff1', 'diff2'] }}
d2 = { "root" : { "leaf": ['diff3'], "node": { "leaf" : ['diff1'] } } }
print(merge_dicts(d1, d2))
You haven't defined what to do if you call merge_dicts({'key': 'value'}, {'key': 'different_value'})
. I have it raising a ValueError, since I would think you can't merge these two dicts (which value would you take?) but you can change that if you want to pick the value from one of the dicts as default, for example.
Upvotes: 1
Reputation: 9597
Untested, but something like this should work:
def dictmerge(d1, d2):
if d1 is None:
return d2
if d2 is None:
return d1
if isinstance(d1, list) and isinstance(d2, list):
return d1+d2
if isinstance(d1, dict) and isinstance(d2, dict):
return {k: dictmerge(d1.get(k), d2.get(k))
for k in set(d1.keys()) | set(d2.keys())}
raise ValueError, "inputs have incompatible structure"
Upvotes: 1