mchfrnc
mchfrnc

Reputation: 5713

The best way to merge multi-nested dictionaries in Python 2.7

I have two nested dictionaries and I want to merge them into one (where second dict overrides first dict values). I saw a lot of beautiful solutions for merging "flat" (not nested) dictionaries, e.g.:

dict_result = dict1.copy()
dict_result.update(dict2)

or

dict_result = dict(dict1.items() + dict2.items())

or (my favorit one)

dict_result = dict(d1,**d2)

but couldn't find the most efficient way to merge multi-nested dicts.

I'm trying to avoid recursion. What is your proposition?

Upvotes: 11

Views: 8483

Answers (2)

anmol
anmol

Reputation: 761

Modified version of the above merge_copy function for dicts that can be thought of as merging parent and child where you want the parent to inherit all the values from child to create a new dict.

def merge_copy(child, parent):
    '''returns parent updated with child values if exists'''
    d = {}
    for k in parent:
        if k in child and isinstance(child[k], dict) and isinstance(parent[k], dict):
            v = merge_copy(child[k], parent[k])
        elif k in child:
            v = child[k]
        else:
            v = parent[k]
        d[k] = v
    return d

Upvotes: 1

tobias_k
tobias_k

Reputation: 82899

Unless the depth of the dictionaries to merge is strictly limited, there's no way to avoid recursion.1) Also, there's no bultin or library function to do this (that is, none that I know of), but it's actually not all that hard. Something like this should do:

def merge(d1, d2):
    for k in d2:
        if k in d1 and isinstance(d1[k], dict) and isinstance(d2[k], dict):
            merge(d1[k], d2[k])
        else:
            d1[k] = d2[k]   

What this does: It iterates the keys in d2 and if the key can also be found in d1 and both are dictionaries, merge those sub-dictionaries, otherwise overwrite the value in d1 with that from d2. Note that this changes d1 and its sub-dictionaries in place, so you might want to deep-copy it before.

Or use this version to create a merged copy:

def merge_copy(d1, d2):
    return {k: merge_copy(d1[k], d2[k]) if k in d1 and isinstance(d1[k], dict) and isinstance(d2[k], dict) else d2[k] for k in d2}

Example:

>>> d1 = {"foo": {"bar": 23, "blub": 42}, "flub": 17}
>>> d2 = {"foo": {"bar": 100}, "flub": {"flub2": 10}, "more": {"stuff": 111}}
>>> merge(d1, d2)
>>> print d1
{'foo': {'bar': 100, 'blub': 42}, 'flub': {'flub2': 10}, 'more': {'stuff': 111}}

1) You can make it iterative, using a stack, but this will only make things more complicated and should only be done to avoid problems with maximum recursive depth.

Upvotes: 15

Related Questions