groupby Then Aggregate With defaultdict (Python)

Pure stdlib group-then-aggregate: defaultdict(list) for the grouping pass, then a tiny per-group reducer. The version I reach for before importing pandas, plus the multi-stat variant.

Python
Compiler
3 snippets
py-collections
py-itertools
code-template
elenamuller

By @elenamuller

February 8, 2026

·

Updated August 19, 2026

283 views

6

4.4 (8)

from __future__ import annotations
from collections import defaultdict
from statistics import mean

# I never use itertools.groupby for this case. itertools.groupby requires the
# input to be PRE-SORTED by the key, and silently produces wrong groups when
# it is not. defaultdict(list) handles arbitrary input order.

events = [
    {'team': 'platform', 'engineer': 'alice', 'tickets': 7},
    {'team': 'growth',   'engineer': 'bob',   'tickets': 4},
    {'team': 'platform', 'engineer': 'carol', 'tickets': 9},
    {'team': 'growth',   'engineer': 'dan',   'tickets': 2},
    {'team': 'platform', 'engineer': 'eve',   'tickets': 5},
]

buckets: dict[str, list[dict]] = defaultdict(list)
for row in events:
    buckets[row['team']].append(row)

# Now reduce each group however you want.
for team, rows in buckets.items():
    total = sum(r['tickets'] for r in rows)
    avg = round(mean(r['tickets'] for r in rows), 1)
    print(f'{team}: {len(rows)} engineers, {total} tickets, avg {avg}')

Two passes: the first builds defaultdict(list) keyed by group, the second walks each group and emits whatever aggregate you need. The reason I prefer this over itertools.groupby is that groupby requires the input to be sorted by the key and silently produces broken results otherwise; defaultdict does not care about input order. The from __future__ import annotations at the top is what lets the dict[str, list[dict]] type hint parse on Python 3.8 (the playground's Python). For datasets up to a few hundred thousand rows this is faster than constructing a DataFrame and lets the aggregation logic stay in plain Python.