How to sum dict elements inside dicts

Question:

In Python I have a list of dictionary containing dictionaries.

list = [{a: {b:1, c:2}}, {d: {b:3, c:4}}, {a: {b:2, c:3}}]

I want one final list with dictionary that contain dictionary that will contain the sum of all dictionary with the same dictionary as the key. i.e. the result will be:

result = [{a: {b:3, c:5}}, {d: {b:3, c:4}}]

N.B: every dictionary in the list will contain same number of key, value pairs.

Asked By: Pat Rose

||

Answers:

I don’t know if it is the best way to do this, but here it goes:

  • First I’ve made a loop for to get all of the primary and secondary keys:

    # list containing the data
    lista = [{'a': {'b':1, 'c':2}}, {'d': {'b':3, 'c':4}}, {'a': {'b':2, 'c':3}}]
    
    # empty list with keys
    primary_keys = []
    secondary_keys = []
    
    # for each dict in the list it appends the primary key and the secondary key
    for dic in lista:
        for key in dic.keys():
            primary_keys.append(key)
            for key2 in dic[key].keys():
                secondary_keys.append(key2)
    
    # prints all the keys
    print('Primary keys:',primary_keys)
    print('Secondary keys:',secondary_keys)

Results:

Primary keys: ['a', 'd', 'a']

Secondary keys: ['b', 'c', 'b', 'c', 'b', 'c']
  • Then I’ve made a final dict with all the combinations:

    # creates the final dict from the list
    dict_final = dict.fromkeys(primary_keys)
    
    # for all primary keys creates a secondary key
    for pkey in dict_final.keys():
        dict_final[pkey] = dict.fromkeys(secondary_keys)
        # for all secondary keys puts a zero
        for skey in dict_final[pkey].keys():
            dict_final[pkey][skey] = 0
    
    # prints the dict
    print(dict_final)

Results:

{'a': {'b': 0, 'c': 0}, 'd': {'b': 0, 'c': 0}}
  • And later I’ve made a loop through each dictionary item and added to the corresponding keys in the final dict

    # for each primary and secondary keys in the dic list sums into the final dict
    for dic in lista:
        for pkey in dict_final.keys():
            for skey in dict_final[pkey].keys():
                try:
                    dict_final[pkey][skey] += dic[pkey][skey]
                except:
                    pass
    
    # prints the final dict
    print(dict_final)

Results:

{'a': {'b': 3, 'c': 5}, 'd': {'b': 3, 'c': 4}}
Answered By: Otavio Maginador

Code:

lst = [{'a': {'b':1, 'c':2}}, {'d': {'b':3, 'c':4}}, {'a': {'b':2, 'c':3}}]
p={}
for l in lst:
    for key , val in l.items():
        if key in p and val != p[key]:
            p.update({key:{k: p[key].get(k, 0) + val.get(k, 0) for k in set(p[key])}})
        else:
            p.update(l)

Output:

{'a': {'c': 5, 'b': 3}, 'd': {'b': 3, 'c': 4}}
Answered By: Stackpy

By using defaultdict, we can simplify the logic a bit:

# Using default dict
from collections import defaultdict

original_list = [{'a': {'b':1, 'c':2}}, {'d': {'b':3, 'c':4}}, {'a': {'b':2, 'c':3}}]

out = defaultdict(lambda: defaultdict(int))
for outter_dict in original_list:
    for outter_key, inner_dict in outter_dict.items():
        for inner_key, inner_value in inner_dict.items():
            out[outter_key][inner_key] += inner_value

print(out)
out_list = [{key: dict(value) for key, value in out.items()}]
print(out_li)

Output:

defaultdict(<function <lambda> at 0x103c18a60>, {'a': defaultdict(<class 'int'>, {'b': 3, 'c': 5}), 'd': defaultdict(<class 'int'>, {'b': 3, 'c': 4})})
[{'a': {'b': 3, 'c': 5}, 'd': {'b': 3, 'c': 4}}]

Notes

  • out is a nested defaultdict whose values are yet defaultdict whose values are integers
  • After the 3 nested loops, we converted the defaultdict out to a list of dictionaries to conform the output requirement
Answered By: Hai Vu