1

Assuming that I have 2 OrderedDict(), I can get the result of the (+) operation by doing the following action:

dict1 = OrderedDict([(52, 0),
         (53, 0),
         (1, 0),
         (2, 0),
         (3, 0),
         (4, 0),
         (5, 0),
         (6, 0),
         (7, 0),
         (8, 0),
         (9, 0),
         (10, 0),
         (11, 1)])

dict2 = OrderedDict([(52, 0),
         (53, 0),
         (1, 0),
         (2, 5),
         (3, 0),
         (4, 0),
         (5, 0),
         (6, 1),
         (7, 0),
         (8, 0),
         (9, 0),
         (10, 1),
         (11, 1)])

dict3 = OrderedDict((k, dict1[k] + dict2[k]) for k in dict1 if k in dict2)
print(dict3)
OrderedDict([(52, 0),
         (53, 0),
         (1, 0),
         (2, 5),
         (3, 0),
         (4, 0),
         (5, 0),
         (6, 1),
         (7, 0),
         (8, 0),
         (9, 0),
         (10, 1),
         (11, 2)])

My question is: how can I generalize the above action so I can get the (+) operation result for N OrderedDict()?

Thierry Lathuille
  • 23,663
  • 10
  • 44
  • 50
azal
  • 1,210
  • 6
  • 23
  • 43

3 Answers3

1

By testing each key for membership of each other dict you're essentially performing an operation of a set intersection, but you can't actually use set intersections because sets are unordered in Python.

You can work around this limitation by installing the ordered-set package, so that you can use the OrderedSet.intersection method to obtain common keys among the dicts ordered by keys in the first dict, which you can then iterate over to construct a new OrderedDict with each value being the sum of the values of the current key from all dicts:

from ordered_set import OrderedSet

dicts = [dict1, dict2]
common_keys = OrderedSet.intersection(*dicts)
print(OrderedDict((k, sum(d[k] for d in dicts)) for k in common_keys))

Demo: https://replit.com/@blhsing/FlawlessGrowlingAccounting

blhsing
  • 91,368
  • 6
  • 71
  • 106
0

Some naive approach using map-reduce. Note that I didn't test the following code, so it might need some adjustments

import operator

dicts = [dict1, dict2, dict3, dict4]
dicts_keys = map(lambda d: set(d.keys()), dicts)
common_keys = set.intersection(*dicts_keys)
sum_dict = OrderedDict(
    (k, reduce(operator.add, map(lambda d: d[k], dicts)))
    for k in common_keys) 
Alexey S. Larionov
  • 6,555
  • 1
  • 18
  • 37
  • 2
    Sets are unordered in Python so by using set operations you would not get a predictably ordered result that iterating over an `OrderedDict` would. – blhsing Mar 18 '21 at 10:11
0

In case you don't want to install an external package, a similar result can be achieved by using this function:

 def add_dicts(*args):
     items_list = list()
     for k in args[0]:
         if all([k in arg for arg in args[1:]]):
             value = 0
             for arg in args:
                     value += arg[k]
             items_list.append((k, value))
     return OrderedDict(items_list)

To call it:

dict3 = add_dicts(dict1, dict2)
dict4 = add_dicts(dict1, dict2, dict3)

If you want to call it with a list of dictionaries:

dict_list=[dict1, dict2]
dict5 = add_dicts(*dict_list)

More information about *args can be found in this answer