Roodra P
Roodra P

Reputation: 49

How to merge complex nested dictionaries

I have two dictionaries:

dict1 = {'cm': {'fill': {'user': {'registration': {'flag': 'f'}}}}}
dict2 = {'cm': {'fill': {'user': {'url': 'www.example.com'}}}}

The output I want:

dict3 = {'cm': {'fill': {'user':{'registration': {'flag': 'f'}}, {'url': 'www.example.com'}}}

Here is what I have tried so far:

dict3 = {**dict1, **dict2} # This does not work. It only gives me a `dict1`.

The problem is that dict1 and dict2 can have many embedded keys.

Any idea how to do this?

Upvotes: 2

Views: 133

Answers (3)

Ajax1234
Ajax1234

Reputation: 71451

You can use recursion while ziping the data:

dict1 = {'cm': {'fill': {'user': {'registration': {'flag': 'f'}}}}}
dict2 = {'cm': {'fill': {'user': {'url': 'www.example.com'}}}}
def update_dict(d1, d2):
   return {a:update_dict(b, d) if a == c and list(b.keys())[0] == list(d.keys())[0] else {**b, **d} for [a, b], [c, d] in zip(d1.items(), d2.items())}

Output:

{'cm': {'fill': {'user': {'registration': {'flag': 'f'}, 'url': 'www.example.com'}}}}

Upvotes: 0

jpp
jpp

Reputation: 164653

If the structure of your dictionaries is consistent, you can use collections.defaultdict with a nested approach.

It's possible to convert the nested defaultdict to regular dict objects. But this may not be necessary for your use case.

from collections import defaultdict

dict1 = {'cm': {'fill': {'user': {'registration': {'flag': 'f'}}}}}
dict2 = {'cm': {'fill': {'user': {'url': 'www.example.com'}}}}

rec_dd = lambda: defaultdict(rec_dd)
d = rec_dd()

for i in [dict1, dict2]:
    d['cm']['fill']['user'].update(i['cm']['fill']['user'])

# defaultdict(<function __main__.<lambda>>,
#             {'cm': defaultdict(<function __main__.<lambda>>,
#                          {'fill': defaultdict(<function __main__.<lambda>>,
#                                       {'user': defaultdict(<function __main__.<lambda>>,
#                                                    {'registration': {'flag': 'f'},
#                                                     'url': 'www.example.com'})})})})

Upvotes: 1

Prune
Prune

Reputation: 77837

Correct: that merge won't do what you want. You have accumulation to do multiple levels down. I suspect that the easiest way for you to get what you want -- merging at unspecified (arbitrary) depth -- is to write a recursive routine to do the merge you want.

def dict_merge(d1, d2):
    for key in d1:
        if key in d2:
            one_merge = dict_merge(d1[key], d2[key])
        else:
            one_merge = d1[key]
    for ... # also pick up keys in d2 that are not in d1.

I'll leave it to you whether to handle this logic with set intersection and difference.

Upvotes: 2

Related Questions