Astrea Astrea - 3 months ago 7
Python Question

Merging Dicts that have Lists of Dicts in Python 2.7

I am trying to merge two Dicts in Python that could be The same or one could have far less info

ex.

master = {"a": 5564, "c": [{"d2":6}]}
daily = { "a": 795, "b": 1337, "c": [{"d1": 2,"d2": 2,"d3": [{"e1": 4,"e2": 4}]}]}


They need to be merged so the output is as such

master = { "a": 6359, "b": 1337, "c": [{"d1": 2,"d2": 8,"d3": [{"e1": 4,"e2": 4}]}]}


I took a shot at it though I only ever get returned null. I might be missing something or just way off. I just cant figure it out. Any help would be amazing Thank you.

def merge(master,daily):
for k, v in daily.items():
if isinstance(daily[k],list):
key_check = keyCheck(k, master)
if key_check:
merge(master[k],daily[k])
else :
master[k] = daily[k]
else :
if keyCheck(k, master):
master[k] += daily[k]
else :
master[k] = daily[k]


keyCheck only checks if a key is in the dictionary so it doesn't throw errors.

Answer

Here is a one linear using collections.Counter():

>>> from collections import Counter
>> C2 = Counter(daily)
>>> C1 = Counter(master)
>>> 
>>> {k:reduce(lambda x,y : Counter(x)+Counter(y), v) if isinstance(v, list) and k in (C1.viewkeys() & C2) else v for k, v in (C1 + C2).items()}
{'a': 6359, 'c': Counter({'d3': [{'e1': 4, 'e2': 4}], 'd2': 8, 'd1': 2}), 'b': 1337}

First off, you can convert your dictionaries to Counter object in order to add the values for common keys after summing the counters (that's how Counter's add attribute works), then you can loop over the items and for keys that are exist in both counters and their values are lists you can use reduce() function to apply the same algorithm on all of the list items too.

If your list might be contain another nested same data structure you can convert this code to a recursion function.