Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Merge multiple dictionaries conditionally

I have N dictionaries that contain the same keys, with values that are integers. I want to merge these into a single dictionary based on the maximum value. Currently I have something like this:

max_dict = {}
for dict in original_dict_list:
    for key, val in dict.iteritems():
        if key not in max_dict or max_dict[key] < val:
            max_dict[key] = val

Is there a better (or more "pythonic") way of doing this?

like image 892
rongved Avatar asked Jan 29 '14 13:01

rongved


People also ask

Can == operator be used on dictionaries?

According to the python doc, you can indeed use the == operator on dictionaries.

Can I use two dictionaries to merge?

Using | in Python 3.9 In the latest update of python now we can use “|” operator to merge two dictionaries. It is a very convenient method to merge dictionaries. Example: Python3.

How do I merge two dictionaries in a single expression take Union of dictionaries )?

Python 3.9 has introduced the merge operator (|) in the dict class. Using the merge operator, we can combine dictionaries in a single line of code. We can also merge the dictionaries in-place by using the update operator (|=).


2 Answers

Use collection.Counter() objects instead, they support 'merging' counts natively:

from collections import Counter

max_dict = Counter()
for d in original_dict_list:
    max_dict |= Counter(d)

or even:

from collections import Counter
from operator import or_

max_dict = reduce(or_, map(Counter, original_dict_list))

Counter objects are multi-sets (also called 'bags' sometimes). The | operator performs a union on two counters, storing the maximum count for a given key.

A Counter is also a straight subclass of dict, so you can (mostly) treat it like any other dictionary.

Demo:

>>> from collections import Counter
>>> from operator import or_
>>> original_dict_list = [{'foo': 3, 'bar': 10}, {'foo': 42, 'spam': 20}, {'bar': 5, 'ham': 10}]
>>> reduce(or_, map(Counter, original_dict_list))
Counter({'foo': 42, 'spam': 20, 'bar': 10, 'ham': 10})
like image 134
Martijn Pieters Avatar answered Oct 13 '22 15:10

Martijn Pieters


Assuming not all dictionaries contain all keys:

keys = set(k for x in original_dict_list for k in x)
max_dict = {k:max([x[k] for x in original_dict_list if k in x]) for k in keys}
like image 29
perreal Avatar answered Oct 13 '22 17:10

perreal