How to combine two nested dictionaries with same master keys

Question:

I have two nested dicts with same master keys:

dict1 = {'person1': {'name': 'John', 'sex': 'Male'},
         'person2': {'name': 'Marie', 'sex': 'Female'},
         'person3': {'name': 'Luna', 'sex': 'Female'},
         'person4': {'name': 'Peter', 'sex': 'Male'}}

dict2 = {'person1': {'weight': '81.1', 'age': '27'},
         'person2': {'weight': '56.7', 'age': '22'},
         'person3': {'weight': '63.4', 'age': '24'},
         'person4': {'weight': '79.1', 'age': '29'}}

So I want to enrich dict 1 by the key value pairs from dict2.

I’m able to do so with a for loop…

for key in dict2:
        dict2[key]['age'] = dict1[key]['age']
        dict2[key]['weight'] = dict2[key]['weight']

Result:

dict2 = {'person1': {'name': 'John', 'sex': 'Male', 'weight': '81.1', 'age': '27'},
         'person2': {'name': 'Marie', 'sex': 'Female', 'weight': '56.7', 'age': '22'},
         'person3': {'name': 'Luna', 'sex': 'Female', 'weight': '63.4', 'age': '24'},
         'person4': {'name': 'Peter', 'sex': 'Male', 'weight': '79.1', 'age': '29'}}

…but is there a more pythonic way to do so – e.g. with dict comprehension?

Asked By: fleshstorm

||

Answers:

Yes:

dict3 = {k: {**v, **dict2[k]} for k, v in dict1.items()}

Firstly, use .items() to iterate over both keys and values at the same time.

Then, for each key k you want the value to be a new dict that is created by dumping — or destructuring — both v and dict2[k] in it.

UPDATE for Python >= 3.9:

Thanks @mwo for mentioning the pipe | operand:

dict3 = {k: v | dict2[k] for k, v in dict1.items()}
Answered By: re-za

If you have control over the data source flatten the dictionaries and then use the update method. For example:

dict1 = {('person1', 'name'): 'John'}
dict2 = {('person1', 'weight'): 81.1}
dict1.update(dict2)
>>> dict1
{('person1', 'name'): 'John', 
 ('person1', 'weight'): 81.1}

It is much easier to deal with this kind of data structure, but if you are stuck with nested dictionaries you can use a NestedDict to achieve the same result with a similar interface.

from ndicts import NestedDict

nd1 = NestedDict(dict1) 
nd2 = NestedDict(dict2) 
nd1.update(nd2)
>>> nd1
NestedDict(
    {'person1': {'name': 'John', 'weight': 81.1}}
)

Use nd1.to_dict() if you need the result as a dictionary.

To install ndicts pip install ndicts.

Answered By: edd313
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.