1

Inspired from this question

I have an arbitrary number of dictionaries (coming from a generator)

a = {"a": 1, "b": 2, "c": 3}
b = {"c": 1, "d": 1}
c = {"a": 2, "b": 2}
...

I want to have a final dictionary that contains the following values for each key:

  • If the key appears only in one dictionary, keep this value
  • If the key appears in multiple dictionaries, the final value is the sum of the values in the individual dicts.

In my example, the result would be {"a": 3, "b": 4, "c": 4, "d": 1}

Based on the answer of the question linked above, I can use collections.Counter when having a set number of dictionaries, like this:

from collections import Counter

dict(Counter(a) + Counter(b) + Counter(c))

However, the number of dictionaries I have can be very large, is there any smart one-liner (or close) I can use to get this "sum" I am interested in ?

Sadly, using sum(Counter(d) for d in (a,b,c)) raises a TypeError: unsupported operand type(s) for +: 'int' and 'Counter'

LoicM
  • 1,786
  • 16
  • 37

3 Answers3

3

You were on the right track with sum, with one exception. sum has a parameter of start that is the value summing starts at, which defaults to 0. This means Python tried to add Counter object to 0, thus error. Changing this value to Counter() lets us use Counter's __add__ method to achieve what we need.

from collections import Counter

a = {"a": 1, "b": 2, "c": 3}
b = {"c": 1, "d": 1}
c = {"a": 2, "b": 2}

dicts = [a,b,c]

counters = [Counter(single_dict) for single_dict in dicts]

total = sum(counters, start = Counter())

print(total) # Counter({'b': 4, 'c': 4, 'a': 3, 'd': 1})
matszwecja
  • 6,357
  • 2
  • 10
  • 17
  • Perfect this is exactly what I was looking for ! Seems like reading the doc for even the most basic functions helps :) Thank you ! – LoicM May 23 '23 at 11:40
1

At the moment I have come up with

total = Counter()

for d in (a,b,c):
     total += Counter(d)
     # Also works with total.update(d)

Which is fine, but cannot be used with e.g a comprehensive list so I keep the question open

LoicM
  • 1,786
  • 16
  • 37
0

Without importing anything and achieving a plain Python dictionary as the final output, you could do this:

a = {"a": 1, "b": 2, "c": 3}
b = {"c": 1, "d": 1}
c = {"a": 2, "b": 2}

z = dict()

for d in a, b, c:
    for k, v in d.items():
        z[k] = z.get(k, 0) + v

print(z)

Output:

{'a': 3, 'b': 4, 'c': 4, 'd': 1}
DarkKnight
  • 19,739
  • 3
  • 6
  • 22