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.
I had two dictionaries (
a
andb
) which could each contain any number of nested dictionaries. I wanted to recursively merge them, withb
taking precedence overa
.Considering the nested dictionaries as trees, what I wanted was:
a
so that every path to every leaf inb
would be represented ina
a
if a leaf is found in the corresponding path inb
b
leaf nodes remain leafs.The existing answers were a little complicated for my taste and left some details on the shelf. I hacked together the following, which passes unit tests for my data set.
Example (formatted for clarity):
The paths in
b
that needed to be maintained were:1 -> 'b' -> 'white'
2 -> 'd' -> 'black'
3 -> 'e'
.a
had the unique and non-conflicting paths of:1 -> 'a' -> 'red'
1 -> 'c' -> 'orange' -> 'dog'
so they are still represented in the merged map.
One issue with this question is that the values of the dict can be arbitrarily complex pieces of data. Based upon these and other answers I came up with this code:
My use case is merging YAML files where I only have to deal with a subset of possible data types. Hence I can ignore tuples and other objects. For me a sensible merge logic means
Everything else and the unforeseens results in an error.
Here's an easy way to do it using generators:
This prints:
The code will depend on your rules for resolving merge conflicts, of course. Here's a version which can take an arbitrary number of arguments and merges them recursively to an arbitrary depth, without using any object mutation. It uses the following rules to resolve merge conflicts:
{"foo": {...}}
takes precedence over{"foo": "bar"}
){"a": 1}
,{"a", 2}
, and{"a": 3}
in order, the result will be{"a": 3}
)This simple recursive procedure will merge one dictionary into another while overriding conflicting keys:
Output:
There's a slight problem with andrew cookes answer: In some cases it modifies the second argument
b
when you modify the returned dict. Specifically it's because of this line:If
b[key]
is adict
, it will simply be assigned toa
, meaning any subsequent modifications to thatdict
will affect botha
andb
.To fix this, the line would have to be substituted with this:
Where
clone_dict
is:Still. This obviously doesn't account for
list
,set
and other stuff, but I hope it illustrates the pitfalls when trying to mergedicts
.And for completeness sake, here is my version, where you can pass it multiple
dicts
: