Python Counter: Count Anything in One Line
collections.Counter turns any iterable into a frequency table in one line — Counter(items) — replacing the manual "check if key exists, then increment" dict loop that most people write first. It is a dict subclass, so everything you know about dictionaries still works, plus it adds counting superpowers: most_common(), arithmetic between counters, and a default of zero for missing keys.
Quick answer: from collections import Counter; Counter(iterable) returns a dict-like object mapping each element to its count. c.most_common(n) gives the top n as (item, count) pairs, c[missing] returns 0 instead of raising KeyError, and counters support +, -, &, and | for combining counts.
How does collections.Counter work?
Pass any iterable — a list, a string, a generator, words from a file — and Counter tallies each distinct element. Because it subclasses dict, you read counts with square brackets, and unlike a plain dict, asking for something it has never seen returns 0 rather than blowing up.
from collections import Counter
votes = ["red", "blue", "red", "green", "red", "blue"]
c = Counter(votes)
print(c) # Counter({'red': 3, 'blue': 2, 'green': 1})
print(c["red"]) # 3
print(c["purple"]) # 0 — no KeyError
# Works on strings (counts characters) and generators too
print(Counter("mississippi"))
# Counter({'i': 4, 's': 4, 'p': 2, 'm': 1})
# Count words in a sentence
text = "the quick brown fox jumps over the lazy dog the end"
words = Counter(text.split())
print(words["the"]) # 3
You can also update a counter incrementally with c.update(more_items) or plain c[key] += 1 — no existence check needed.
How do I get the most common items with most_common()?
most_common(n) returns the n highest-count elements as a list of (item, count) tuples, sorted from most to least frequent. Call it with no argument to get every element in descending order — an instant sorted frequency report.
from collections import Counter
log_levels = ["INFO", "ERROR", "INFO", "WARN", "INFO", "ERROR", "INFO"]
c = Counter(log_levels)
print(c.most_common(2)) # [('INFO', 4), ('ERROR', 2)]
print(c.most_common()) # [('INFO', 4), ('ERROR', 2), ('WARN', 1)]
# Unpack the single most common element
top, count = c.most_common(1)[0]
print(f"{top} appeared {count} times") # INFO appeared 4 times
# Least common: slice from the end
print(c.most_common()[-1]) # ('WARN', 1)
Can I add and subtract Counters?
Yes — counters support real arithmetic, which is where they beat plain dicts outright. + merges counts, - subtracts and drops anything that falls to zero or below, & takes the element-wise minimum (intersection), and | the maximum (union). Perfect for diffing inventories, merging tallies from multiple files, or finding overlap.
from collections import Counter
monday = Counter({"apple": 3, "banana": 2, "cherry": 1})
tuesday = Counter({"apple": 1, "banana": 4, "date": 2})
print(monday + tuesday) # Counter({'banana': 6, 'apple': 4, 'date': 2, 'cherry': 1})
print(monday - tuesday) # Counter({'apple': 2, 'cherry': 1}) — negatives dropped
print(monday & tuesday) # Counter({'banana': 2, 'apple': 1}) — min of each
print(monday | tuesday) # Counter({'banana': 4, 'apple': 3, 'date': 2, 'cherry': 1})
# Keep negatives instead of dropping them
monday.subtract(tuesday)
print(monday) # Counter({'apple': 2, 'cherry': 1, 'banana': -2, 'date': -2})
Counter arithmetic also gives you a two-line anagram check: Counter(a) == Counter(b) is true exactly when both strings contain the same characters with the same frequencies.
Counter vs value_counts() vs a dict loop: which should I use?
Use Counter for plain Python data — lists, strings, streams — where you want counts with zero dependencies. Use pandas value_counts() when the data already lives in a DataFrame and you want sorting, percentages, or plotting for free. Write a manual dict loop only when you are counting something more complex than occurrences (say, summing amounts per key).
from collections import Counter
items = ["a", "b", "a", "c", "a"]
# The loop Counter replaces:
counts = {}
for item in items:
counts[item] = counts.get(item, 0) + 1
# One line instead:
counts = Counter(items)
# In pandas land, reach for value_counts():
import pandas as pd
s = pd.Series(items)
print(s.value_counts())
# a 3
# b 1
# c 1
The .get(key, 0) pattern and its cousins are covered in our Python dictionary methods guide; if your counting problem lives in a DataFrame column, pandas value_counts() is the idiomatic tool. One caveat at scale: for millions of values already in a Series, value_counts() runs vectorized and will beat converting to a list just to feed Counter.
Pro Tip: Counter accepts generators, so you can count huge files without loading them: Counter(word for line in open("big.txt") for word in line.split()). Combined with most_common(10), that is a complete word-frequency tool in two lines of standard library.