Python Basics: Counting and Grouping with collections
Counting repeated values and grouping records are common jobs in small scripts. Python’s standard-library collections module provides Counter and defaultdict to keep that code short.
Use Python 3.12 or newer on Linux. The saved scripts operate on sample data in memory and do not read or change data files.
Count repeated values
Save as demo_collections_1.py:
from collections import Counter
statuses = ["ok", "retry", "ok", "failed", "ok", "retry"]
counts = Counter(statuses)
for status, count in counts.most_common():
print(status, count)
print("skipped:", counts["skipped"])
print("Total:", counts.total())Run:
python3 demo_collections_1.pyOutput:
ok 3
retry 2
failed 1
skipped: 0
Total: 6Counter maps values to counts. A missing value returns zero without adding a key. most_common() sorts by count, highest first; ties retain the order in which values were first encountered. Use most_common(2) when you only need the top two.
Add another batch
Counter.update() adds counts instead of replacing them as dict.update() does. Sorting the keys makes this report alphabetical.
Save as demo_collections_2.py:
from collections import Counter
counts = Counter(["ok", "retry", "ok"])
counts.update(["failed", "ok"])
counts.subtract(["retry"])
for status in sorted(counts):
print(status, counts[status])
print("Positive counts:", dict(+counts))Run:
python3 demo_collections_2.pyOutput:
failed 1
ok 3
retry 0
Positive counts: {'ok': 3, 'failed': 1}Subtracting can leave zero or negative counts. Unary + creates a new counter containing only positive counts; it does not change the original. Pass a list of labels to count labels: passing one string counts its individual characters.
Group records by a field
Save as demo_collections_3.py:
from collections import defaultdict
records = [
("api", "check health"),
("worker", "retry job"),
("api", "rotate logs"),
]
by_service = defaultdict(list)
for service, task in records:
by_service[service].append(task)
for service in sorted(by_service):
print(service + ": " + ", ".join(by_service[service]))
print("Missing:", by_service.get("cache"))
print("Groups:", len(by_service))Run:
python3 demo_collections_3.pyOutput:
api: check health, rotate logs
worker: retry job
Missing: None
Groups: 2Pass list, not list(), as the factory. A missing-key lookup with square brackets creates and stores a new list. get() does not call the factory or add a group. Keep a plain dictionary when automatically creating missing values would hide a mistake.
References
Acknowledgements
This post was created with assistance from AI.