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.
As this is the canonical question (in spite of certain non-generalities) I'm providing the canonical Pythonic approach to solving this issue.
Simplest Case: "leaves are nested dicts that end in empty dicts":
This is the simplest case for recursion, and I would recommend two naive approaches:
I believe I would prefer the second to the first, but keep in mind that the original state of the first would have to be rebuilt from its origin. Here's the usage:
Complex Case: "leaves are of any other type:"
So if they end in dicts, it's a simple case of merging the end empty dicts. If not, it's not so trivial. If strings, how do you merge them? Sets can be updated similarly, so we could give that treatment, but we lose the order in which they were merged. So does order matter?
So in lieu of more information, the simplest approach will be to give them the standard update treatment if both values are not dicts: i.e. the second dict's value will overwrite the first, even if the second dict's value is None and the first's value is a dict with a lot of info.
And now
returns
Application to the original question:
I've had to remove the curly braces around the letters and put them in single quotes for this to be legit Python (else they would be set literals in Python 2.7+) as well as append a missing brace:
and
rec_merge(dict1, dict2)
now returns:Which matches the desired outcome of the original question (after changing, e.g. the
{A}
to'A'
.)Based on answers from @andrew cooke. It takes care of nested lists in a better way.
Overview
The following approach subdivides the problem of a deep merge of dicts into:
A parameterized shallow merge function
merge(f)(a,b)
that uses a functionf
to merge two dictsa
andb
A recursive merger function
f
to be used together withmerge
Implementation
A function for merging two (non nested) dicts can be written in a lot of ways. I personally like
A nice way of defining an appropriate recurrsive merger function
f
is using multipledispatch which allows to define functions that evaluate along different paths depending on the type of their arguments.Example
To merge two nested dicts simply use
merge(f)
e.g.:Notes:
The advantages of this approach are:
The function is build from smaller functions that each do a single thing which makes the code simpler to reason about and test
The behaviour is not hard-coded but can be changed and extended as needed which improves code reuse (see example below).
Customization
Some answers also considered dicts that contain lists e.g. of other (potentially nested) dicts. In this case one might want map over the lists and merge them based on position. This can be done by adding another definition to the merger function
f
:I have another slightly different solution here:
By default it resolves conflicts in favor of values from the second dict, but you can easily override this, with some witchery you may be able to even throw exceptions out of it. :).
I've been testing your solutions and decided to use this one in my project:
Passing functions as parameteres is key to extend jterrace solution to behave as all the other recursive solutions.