user650108 user650108 - 6 months ago 14
Python Question

Best way to aggregate a simple dict in Python

My problem is simple: I have a list of dicts, and I want to make a count aggregation of this into a new dictionary, on a particular key. Just like this, but in Python.

Original data



mylist = [
{'date': '16-01-2016', 'name': 'A'},
{'date': '16-01-2016', 'name': 'B'},
{'date': '17-01-2016', 'name': 'C'},
{'date': '17-01-2016', 'name': 'D'},
{'date': '17-01-2016', 'name': 'E'},
{'date': '18-01-2016', 'name': 'F'},
]


Result



{'17-01-2016': 3, '16-01-2016': 2, '18-01-2016': 1}


How to?



What is the best solution to achieve this? I would like to do it a more beautiful and pythonic way than that ugly piece of code:

result = {}
for item in mylist:
if not item['date'] in result:
result[item['date']] = 1
else:
result[item['date']] += 1


Many thanks for considering my request!

Answer

You can use a collections.Counter dict with map and operator.itemgetter:

from collections import Counter
from operator import itemgetter

mylist = [
    {'date': '16-01-2016', 'name': 'A'},
    {'date': '16-01-2016', 'name': 'B'},
    {'date': '17-01-2016', 'name': 'C'},
    {'date': '17-01-2016', 'name': 'D'},
    {'date': '17-01-2016', 'name': 'E'},
    {'date': '18-01-2016', 'name': 'F'},
]

counts = Counter(map(itemgetter("date"), mylist))

Output:

Counter({'17-01-2016': 3, '16-01-2016': 2, '18-01-2016': 1})

Or using just a gen exp:

counts = Counter(d["date"] for d in mylist)

If you are using python2, use itertools.imap in place of map.

On a side note, if item['date'] not in result reads better than if not item['date'] in result.

If speed really matters, the map and itemgetter will be a little faster:

In [16]: timeit  Counter(map(itemgetter("date"), mylist))
10 loops, best of 3: 23.9 ms per loop

In [17]: timeit  Counter(d["date"] for d in mylist)
10 loops, best of 3: 26.8 ms per loop

In [18]: timeit Counter(map(lambda x: x['date'], mylist))
10 loops, best of 3: 34.9 ms per loop
Comments