I need to merge multiple dictionaries, here’s what I have for instance:
dict1 = {1:{"a":{A}}, 2:{"b":{B}}} dict2 = {2:{"c":{C}}, 3:{"d":{D}}}
With A
B
C
and D
being leaves of the tree, like {"info1":"value", "info2":"value2"}
There is an unknown level(depth) of dictionaries, it could be {2:{"c":{"z":{"y":{C}}}}}
In my case it represents a directory/files structure with nodes being docs and leaves being files.
I want to merge them to obtain:
dict3 = {1:{"a":{A}}, 2:{"b":{B},"c":{C}}, 3:{"d":{D}}}
I’m not sure how I could do that easily with Python.
Advertisement
Answer
This is actually quite tricky – particularly if you want a useful error message when things are inconsistent, while correctly accepting duplicate but consistent entries (something no other answer here does..)
Assuming you don’t have huge numbers of entries, a recursive function is easiest:
from functools import reduce def merge(a, b, path=None): "merges b into a" if path is None: path = [] for key in b: if key in a: if isinstance(a[key], dict) and isinstance(b[key], dict): merge(a[key], b[key], path + [str(key)]) elif a[key] == b[key]: pass # same leaf value else: raise Exception('Conflict at %s' % '.'.join(path + [str(key)])) else: a[key] = b[key] return a # works print(merge({1:{"a":"A"},2:{"b":"B"}}, {2:{"c":"C"},3:{"d":"D"}})) # has conflict merge({1:{"a":"A"},2:{"b":"B"}}, {1:{"a":"A"},2:{"b":"C"}})
note that this mutates a
– the contents of b
are added to a
(which is also returned). If you want to keep a
you could call it like merge(dict(a), b)
.
agf pointed out (below) that you may have more than two dicts, in which case you can use:
reduce(merge, [dict1, dict2, dict3...])
where everything will be added to dict1
.
Note: I edited my initial answer to mutate the first argument; that makes the “reduce” easier to explain