Mathew K Analytics

Lesson 4 · Python standard library deep dive

Python collections Explained: Counter, deque & defaultdict | Standard Library #4

Video four of the twenty-five-part series: collections, specialized container types that solve problems the built-in list, dict, and tuple genuinely don't…

⬇ Download notebookOpen in Colab ↗

What you'll learn

Data

No separate download needed — the notebook creates or downloads everything it uses.

📓 Full notebook

Download .ipynb

Python Standard Library Deep-Dive, Video 4: collections#

  • Video four of the twenty-five-part series: collections, specialized container types that solve problems the built-in list, dict, and tuple genuinely don't cover well.
  • Counter, defaultdict, deque, namedtuple, OrderedDict, and ChainMap.
  • Let's get into it.

Part 1: What collections Offers#

from collections import Counter, defaultdict, deque, namedtuple, OrderedDict, ChainMap
print('all six imported successfully')
all six imported successfully

Part 2: Counter#

words = ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']
counts = Counter(words)
print(counts)
print(counts['apple'])
print(counts['durian'])
print(isinstance(counts, dict))
Counter({'apple': 3, 'banana': 2, 'cherry': 1})
3
0
True
counts = Counter('mississippi')
print(counts)
print(counts.most_common())
print(counts.most_common(2))
print(list(counts.elements()))
counts.update('extra')
print(counts)
Counter({'i': 4, 's': 4, 'p': 2, 'm': 1})
[('i', 4), ('s', 4), ('p', 2), ('m', 1)]
[('i', 4), ('s', 4)]
['m', 'i', 'i', 'i', 'i', 's', 's', 's', 's', 'p', 'p']
Counter({'i': 4, 's': 4, 'p': 2, 'm': 1, 'e': 1, 'x': 1, 't': 1, 'r': 1, 'a': 1})
a = Counter(['x', 'x', 'y'])
b = Counter(['x', 'y', 'y', 'z'])
print(a + b)
print(a - b)
print(a & b)
print(a | b)
Counter({'x': 3, 'y': 3, 'z': 1})
Counter({'x': 1})
Counter({'x': 1, 'y': 1})
Counter({'x': 2, 'y': 2, 'z': 1})

Part 3: defaultdict#

groups = defaultdict(list)
groups['fruits'].append('apple')
groups['fruits'].append('banana')
groups['vegetables'].append('carrot')
print(dict(groups))
regular = {}
try:
    regular['fruits'].append('apple')
except KeyError as e:
    print(f'Caught: {e}')
{'fruits': ['apple', 'banana'], 'vegetables': ['carrot']}
Caught: 'fruits'
word_lengths = defaultdict(int)
for word in ['cat', 'dog', 'elephant', 'ox', 'cat']:
    word_lengths[word] += 1
print(dict(word_lengths))
tree = lambda: defaultdict(tree)
nested = tree()
nested['a']['b']['c'] = 'deep value'
print(nested['a']['b']['c'])
{'cat': 2, 'dog': 1, 'elephant': 1, 'ox': 1}
deep value

Part 4: deque#

d = deque([1, 2, 3])
d.append(4)
d.appendleft(0)
print(d)
print(d.pop())
print(d.popleft())
print(d)
deque([0, 1, 2, 3, 4])
4
0
deque([1, 2, 3])
recent = deque(maxlen=3)
for i in range(6):
    recent.append(i)
    print(list(recent))
d = deque([1, 2, 3, 4, 5])
d.rotate(2)
print(d)
d.rotate(-2)
print(d)
[0]
[0, 1]
[0, 1, 2]
[1, 2, 3]
[2, 3, 4]
[3, 4, 5]
deque([4, 5, 1, 2, 3])
deque([1, 2, 3, 4, 5])

Part 5: namedtuple#

Point = namedtuple('Point', ['x', 'y', 'z'])
p = Point(1, 2, 3)
print(p)
print(p._fields)
print(p._asdict())
updated = p._replace(z=99)
print(updated)
print(p)
values = [10, 20, 30]
from_list = Point._make(values)
print(from_list)
Point(x=1, y=2, z=3)
('x', 'y', 'z')
{'x': 1, 'y': 2, 'z': 3}
Point(x=1, y=2, z=99)
Point(x=1, y=2, z=3)
Point(x=10, y=20, z=30)

Part 6: OrderedDict#

od = OrderedDict()
od['first'] = 1
od['second'] = 2
od['third'] = 3
print(od)
od.move_to_end('first')
print(od)
od.move_to_end('third', last=False)
print(od)
OrderedDict({'first': 1, 'second': 2, 'third': 3})
OrderedDict({'second': 2, 'third': 3, 'first': 1})
OrderedDict({'third': 3, 'second': 2, 'first': 1})
od1 = OrderedDict([('a', 1), ('b', 2)])
od2 = OrderedDict([('b', 2), ('a', 1)])
print(od1 == od2)
d1 = {'a': 1, 'b': 2}
d2 = {'b': 2, 'a': 1}
print(d1 == d2)
False
True

Part 7: ChainMap#

defaults = {'theme': 'light', 'font_size': 12, 'language': 'en'}
user_settings = {'font_size': 16}
combined = ChainMap(user_settings, defaults)
print(combined['font_size'])
print(combined['theme'])
print(dict(combined))
user_settings['theme'] = 'dark'
print(combined['theme'])
16
light
{'theme': 'light', 'font_size': 16, 'language': 'en'}
dark

Part 8: Common Patterns#

text = 'the quick brown fox jumps over the lazy dog the fox runs'
word_counts = Counter(text.split())
print(word_counts.most_common(3))
[('the', 3), ('fox', 2), ('quick', 1)]
def moving_average(values, window_size):
    window = deque(maxlen=window_size)
    averages = []
    for value in values:
        window.append(value)
        averages.append(sum(window) / len(window))
    return averages
data = [10, 20, 30, 40, 50, 60]
print(moving_average(data, 3))
[10.0, 15.0, 20.0, 30.0, 40.0, 50.0]

Wrap-Up: What You Learned#

  • Counter: fast tallying, most_common, elements, and set-like arithmetic between counters.
  • defaultdict: automatic default values from a factory function, eliminating manual key checks.
  • deque: fast operations at both ends, maxlen for bounded history, and rotate.
  • namedtuple in depth: _fields, _asdict, _replace, _make.
  • OrderedDict: move_to_end and order-sensitive equality, still relevant despite dict's own ordering.
  • ChainMap: a live, layered view across multiple dictionaries with no copying.
  • Two real patterns: word-frequency counting and a deque-based moving average.
  • That wraps up collections. Next up: itertools, for efficient iteration and combinatorics.

Found this useful?

All lessons, notebooks and datasets here are free. If they helped you, a coffee keeps new lessons coming.