cornelinux
cornelinux

Reputation: 917

python: combine two nested dictionaries with dictionaries as values of the top level keys

I'd like to combine two nested dictionaries

d1 = {"admin": {"key1": "v2"}}
d2 = {"admin": {"key2": "v3"},
      "user": {"something": "else"}}

This should be combine to:

d = {"admin": {"key1": "v2",
               "key2": "v3"},
     "user": {"something": "else"}}

Is there an easy way to do it other than iterating over the first key?

Upvotes: 3

Views: 723

Answers (4)

Michele d'Amico
Michele d'Amico

Reputation: 23711

You can use defaultdict to have every value of first level as a dict. After you can use update() from dict.

>>> from collections import defaultdict
>>> d = defaultdict(dict)
>>> d1 = {"admin": {"key1": "v2"}}
>>> d2 = {"admin": {"key2": "v3"},
...       "user": {"something": "else"}}
>>> for dd in [d1,d2]:
...     for k,v in dd.items():
...         d[k].update(v)
... 
>>> d
defaultdict(<type 'dict'>, {'admin': {'key2': 'v3', 'key1': 'v2'}, 'user': {'something': 'else'}})

Or in a more compact form you can use map()... really I don't like it but is a chance

>>> for dd in [d1,d2]:
...     map(lambda x:d[x[0]].update(x[1]),dd.items())

Upvotes: 4

Ngenator
Ngenator

Reputation: 11259

from copy import deepcopy

d1 = {"admin": {"key1": "v2"}}
d2 = {"admin": {"key2": "v3"},
      "user": {"something": "else"}}

def merge(one, two):
    if isinstance(two, dict):
        result = deepcopy(one)
        for key, value in two.iteritems():
            if key in result and isinstance(result[key], dict):
                result[key] = merge(result[key], value)
            else:
                result[key] = deepcopy(value)
        return result
    return two

print merge(d1, d2)

Output

{'admin': {'key2': 'v3', 'key1': 'v2'}, 'user': {'something': 'else'}}

Upvotes: 1

Padraic Cunningham
Padraic Cunningham

Reputation: 180401

from itertools import chain
from collections import defaultdict
new_d = defaultdict(dict)

for k,v in chain(d1.iteritems(),d2.iteritems()):
    new_d[k].update(v)
print(new_d)
defaultdict(<type 'dict'>, {'admin': {'key2': 'v3', 'key1': 'v2'}, 'user': {'something': 'else'}})

Upvotes: 1

wim
wim

Reputation: 362647

If there is only one level of nesting:

>>> d1 = {"admin": {"key1": "v2"}}
>>> d2 = {"admin": {"key2": "v3"},
...       "user": {"something": "else"}}
>>> keys = list(d1) + list(d2)
>>> d = {k: dict(d1.get(k, {}).items() + d2.get(k, {}).items()) for k in keys}
>>> d
{'admin': {'key1': 'v2', 'key2': 'v3'}, 'user': {'something': 'else'}}

Deeper nesting will need recursion.

Upvotes: 1

Related Questions