Home > Back-end >  Add up values of same key in nested dictionary where keys are elements of a list
Add up values of same key in nested dictionary where keys are elements of a list

Time:12-17

mylist = ['01', '02']
d = {'01': {'age':19, 'answ1':3, 'answ2':7, 'answ3':2},
     '02': {'age':52, 'answ1':8, 'answ2':1, 'answ3':10},
     '03': {'age':32, 'answ1':28, 'answ2':3, 'answ3':15}}

It should print the sum of two dicts which have the keys '01' and '02'.

Output should be {'age':71, 'answ1':11, 'answ2':8, 'answ3':12}.

I know that it can be done by nested for loops but I could not.

CodePudding user response:

Create and empty dictionary initialized to zero. Python can go iterate the items of a list, so it becomes an indexing problem.

mylist = ['01', '02']
d = {'01': {'age':19, 'answ1':3, 'answ2':7, 'answ3':2}, '02': {'age':52, 'answ1':8, 'answ2':1, 'answ3':10}, '03': {'age':32, 'answ1':28, 'answ2':3, 'answ3':15}}
sum_dic ={'age':0, 'answ1':0, 'answ2':0, 'answ3':0}
for item in mylist:
    sum_dic['age']  = d[item]['age']
    sum_dic['answ1']  = d[item]['answ1']
    sum_dic['answ2']  = d[item]['answ2']
    sum_dic['answ3']  = d[item]['answ3']
print(sum_dic)

CodePudding user response:

>>> from collections import defaultdict
>>> totals = defaultdict(int)
>>> for x in (d[k] for k in mylist):
...     for k, v in x.items():
...         totals[k]  = v
... 
>>> dict(totals)
{'age': 71, 'answ1': 11, 'answ2': 8, 'answ3': 12}

CodePudding user response:

Iterate over mylist and the values of d, and add the values in each iteration to the values at the corresponding keys in out.

out = {}
for key in mylist:
    for k,v in d[key].items():
        out[k] = out.get(k, 0)   v

Output:

{'age': 71, 'answ1': 11, 'answ2': 8, 'answ3': 12}

CodePudding user response:

Here is another way to do this in one line of code with the help of functools.reduce, collections.Counter and operator.(add, itemgetter) -

from collections import Counter
from functools import reduce
from operator import add, itemgetter

dict(reduce(add, map(Counter, itemgetter(*mylist)(d))))

#OR 

dict(reduce(add, (Counter(d[i]) for i in mylist)))
{'age': 71, 'answ1': 11, 'answ2': 8, 'answ3': 12}

Explanation

Read more about the second part here.

  • The itemgetter fetches the values in d with keys matching the mylist. Feel free to change that to a generator.

  • A quick example showcases the above code's essence. You can add two Counter dictionaries with a or operator.add as shown below -

Counter({'a':1,'b':3})   Counter({'a':4,'b':1})
Counter({'a': 5, 'b': 4})
  • Related