Standard dictionaries and lists handle most cases, but counting frequencies, grouping items, or maintaining queues require repetitive boilerplate. The collections module provides specialized containers that handle these patterns efficiently with clean, readable code.

specialized containers Data structures optimized for specific use cases like counting, ordering, or double-ended access, extending built-in types.

Counter

Count element frequencies:

items
counter.py
Replay: real traced execution (multi-file project)
# Counter examples

from collections import Counter

# Basic Counter
print("Basic Counter:")

# Count from list
items = ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']
counter = Counter(items)

print(f"Items: {items}")
print(f"Counter: {counter}")
print(f"apple: {counter['apple']}")
print(f"banana: {counter['banana']}")
print(f"grape: {counter['grape']}")  # Returns 0, not KeyError

# Count from string
print("\nCount from string:")

text = "hello world"
char_count = Counter(text)

print(f"Text: '{text}'")
print(f"Characters: {char_count}")
print(f"'l': {char_count['l']}")
print(f"'o': {char_count['o']}")

# Most common
print("\nMost common:")

words = ['the', 'quick', 'brown', 'fox', 'the', 'lazy', 'dog', 'the', 'quick']
word_count = Counter(words)

print(f"Words: {words}")
print(f"Most common 3: {word_count.most_common(3)}")
print(f"All by frequency: {word_count.most_common()}")

# Count votes
print("\nCount votes:")

votes = ['Alice', 'Bob', 'Alice', 'Charlie', 'Alice', 'Bob', 'Alice']
results = Counter(votes)

print(f"Votes: {votes}")
for candidate, count in results.most_common():
    print(f"  {candidate}: {count} votes")

winner = results.most_common(1)[0][0]
print(f"Winner: {winner}")

# Update counter
print("\nUpdate counter:")

c1 = Counter(['a', 'b', 'c'])
print(f"Initial: {c1}")

c1.update(['a', 'b', 'd'])
print(f"After update: {c1}")

c1.update({'a': 2, 'e': 3})
print(f"After dict update: {c1}")

# Subtract
print("\nSubtract:")

inventory = Counter(apples=10, bananas=5, oranges=8)
sold = Counter(apples=3, bananas=2, oranges=1)

print(f"Inventory: {inventory}")
print(f"Sold: {sold}")

inventory.subtract(sold)
print(f"Remaining: {inventory}")

# Counter arithmetic
print("\nCounter arithmetic:")

c1 = Counter(a=3, b=2, c=1)
c2 = Counter(a=1, b=2, d=3)

print(f"C1: {c1}")
print(f"C2: {c2}")
print(f"C1 + C2: {c1 + c2}")
print(f"C1 - C2: {c1 - c2}")
print(f"C1 & C2 (intersection): {c1 & c2}")
print(f"C1 | C2 (union): {c1 | c2}")

# Elements
print("\nElements:")

c = Counter(a=3, b=2, c=1)
print(f"Counter: {c}")
print(f"Elements: {list(c.elements())}")

# Sorted
print(f"Sorted: {sorted(c.elements())}")

# Total count
print("\nTotal count:")

inventory = Counter(apples=10, bananas=5, oranges=8)
print(f"Inventory: {inventory}")
print(f"Total items: {sum(inventory.values())}")

# Or use total() in Python 3.10+
# print(f"Total: {inventory.total()}")

# Most common letter
print("\nMost common letter:")

text = "the quick brown fox jumps over the lazy dog"
letters = Counter(c for c in text.lower() if c.isalpha())

print(f"Text: '{text}'")
print(f"Most common 5 letters: {letters.most_common(5)}")

# Word frequency
print("\nWord frequency:")

document = "the cat and the dog and the bird"
words = document.split()
freq = Counter(words)

print(f"Document: '{document}'")
for word, count in sorted(freq.items(), key=lambda x: x[1], reverse=True):
    print(f"  '{word}': {count}")

# Clear counter
print("\nClear counter:")

c = Counter(a=1, b=2, c=3)
print(f"Before: {c}")

c.clear()
print(f"After clear: {c}")

# Counter examples

from collections import Counter

# Basic Counter
print("Basic Counter:")

# Count from list
items = ['red', 'blue', 'red']
counter = Counter(items)

print(f"Items: {items}")
print(f"Counter: {counter}")
print(f"apple: {counter['apple']}")
print(f"banana: {counter['banana']}")
print(f"grape: {counter['grape']}")  # Returns 0, not KeyError

# Count from string
print("\nCount from string:")

text = "hello world"
char_count = Counter(text)

print(f"Text: '{text}'")
print(f"Characters: {char_count}")
print(f"'l': {char_count['l']}")
print(f"'o': {char_count['o']}")

# Most common
print("\nMost common:")

words = ['the', 'quick', 'brown', 'fox', 'the', 'lazy', 'dog', 'the', 'quick']
word_count = Counter(words)

print(f"Words: {words}")
print(f"Most common 3: {word_count.most_common(3)}")
print(f"All by frequency: {word_count.most_common()}")

# Count votes
print("\nCount votes:")

votes = ['Alice', 'Bob', 'Alice', 'Charlie', 'Alice', 'Bob', 'Alice']
results = Counter(votes)

print(f"Votes: {votes}")
for candidate, count in results.most_common():
    print(f"  {candidate}: {count} votes")

winner = results.most_common(1)[0][0]
print(f"Winner: {winner}")

# Update counter
print("\nUpdate counter:")

c1 = Counter(['a', 'b', 'c'])
print(f"Initial: {c1}")

c1.update(['a', 'b', 'd'])
print(f"After update: {c1}")

c1.update({'a': 2, 'e': 3})
print(f"After dict update: {c1}")

# Subtract
print("\nSubtract:")

inventory = Counter(apples=10, bananas=5, oranges=8)
sold = Counter(apples=3, bananas=2, oranges=1)

print(f"Inventory: {inventory}")
print(f"Sold: {sold}")

inventory.subtract(sold)
print(f"Remaining: {inventory}")

# Counter arithmetic
print("\nCounter arithmetic:")

c1 = Counter(a=3, b=2, c=1)
c2 = Counter(a=1, b=2, d=3)

print(f"C1: {c1}")
print(f"C2: {c2}")
print(f"C1 + C2: {c1 + c2}")
print(f"C1 - C2: {c1 - c2}")
print(f"C1 & C2 (intersection): {c1 & c2}")
print(f"C1 | C2 (union): {c1 | c2}")

# Elements
print("\nElements:")

c = Counter(a=3, b=2, c=1)
print(f"Counter: {c}")
print(f"Elements: {list(c.elements())}")

# Sorted
print(f"Sorted: {sorted(c.elements())}")

# Total count
print("\nTotal count:")

inventory = Counter(apples=10, bananas=5, oranges=8)
print(f"Inventory: {inventory}")
print(f"Total items: {sum(inventory.values())}")

# Or use total() in Python 3.10+
# print(f"Total: {inventory.total()}")

# Most common letter
print("\nMost common letter:")

text = "the quick brown fox jumps over the lazy dog"
letters = Counter(c for c in text.lower() if c.isalpha())

print(f"Text: '{text}'")
print(f"Most common 5 letters: {letters.most_common(5)}")

# Word frequency
print("\nWord frequency:")

document = "the cat and the dog and the bird"
words = document.split()
freq = Counter(words)

print(f"Document: '{document}'")
for word, count in sorted(freq.items(), key=lambda x: x[1], reverse=True):
    print(f"  '{word}': {count}")

# Clear counter
print("\nClear counter:")

c = Counter(a=1, b=2, c=3)
print(f"Before: {c}")

c.clear()
print(f"After clear: {c}")

# Counter examples

from collections import Counter

# Basic Counter
print("Basic Counter:")

# Count from list
items = ['cat', 'dog', 'cat', 'cat']
counter = Counter(items)

print(f"Items: {items}")
print(f"Counter: {counter}")
print(f"apple: {counter['apple']}")
print(f"banana: {counter['banana']}")
print(f"grape: {counter['grape']}")  # Returns 0, not KeyError

# Count from string
print("\nCount from string:")

text = "hello world"
char_count = Counter(text)

print(f"Text: '{text}'")
print(f"Characters: {char_count}")
print(f"'l': {char_count['l']}")
print(f"'o': {char_count['o']}")

# Most common
print("\nMost common:")

words = ['the', 'quick', 'brown', 'fox', 'the', 'lazy', 'dog', 'the', 'quick']
word_count = Counter(words)

print(f"Words: {words}")
print(f"Most common 3: {word_count.most_common(3)}")
print(f"All by frequency: {word_count.most_common()}")

# Count votes
print("\nCount votes:")

votes = ['Alice', 'Bob', 'Alice', 'Charlie', 'Alice', 'Bob', 'Alice']
results = Counter(votes)

print(f"Votes: {votes}")
for candidate, count in results.most_common():
    print(f"  {candidate}: {count} votes")

winner = results.most_common(1)[0][0]
print(f"Winner: {winner}")

# Update counter
print("\nUpdate counter:")

c1 = Counter(['a', 'b', 'c'])
print(f"Initial: {c1}")

c1.update(['a', 'b', 'd'])
print(f"After update: {c1}")

c1.update({'a': 2, 'e': 3})
print(f"After dict update: {c1}")

# Subtract
print("\nSubtract:")

inventory = Counter(apples=10, bananas=5, oranges=8)
sold = Counter(apples=3, bananas=2, oranges=1)

print(f"Inventory: {inventory}")
print(f"Sold: {sold}")

inventory.subtract(sold)
print(f"Remaining: {inventory}")

# Counter arithmetic
print("\nCounter arithmetic:")

c1 = Counter(a=3, b=2, c=1)
c2 = Counter(a=1, b=2, d=3)

print(f"C1: {c1}")
print(f"C2: {c2}")
print(f"C1 + C2: {c1 + c2}")
print(f"C1 - C2: {c1 - c2}")
print(f"C1 & C2 (intersection): {c1 & c2}")
print(f"C1 | C2 (union): {c1 | c2}")

# Elements
print("\nElements:")

c = Counter(a=3, b=2, c=1)
print(f"Counter: {c}")
print(f"Elements: {list(c.elements())}")

# Sorted
print(f"Sorted: {sorted(c.elements())}")

# Total count
print("\nTotal count:")

inventory = Counter(apples=10, bananas=5, oranges=8)
print(f"Inventory: {inventory}")
print(f"Total items: {sum(inventory.values())}")

# Or use total() in Python 3.10+
# print(f"Total: {inventory.total()}")

# Most common letter
print("\nMost common letter:")

text = "the quick brown fox jumps over the lazy dog"
letters = Counter(c for c in text.lower() if c.isalpha())

print(f"Text: '{text}'")
print(f"Most common 5 letters: {letters.most_common(5)}")

# Word frequency
print("\nWord frequency:")

document = "the cat and the dog and the bird"
words = document.split()
freq = Counter(words)

print(f"Document: '{document}'")
for word, count in sorted(freq.items(), key=lambda x: x[1], reverse=True):
    print(f"  '{word}': {count}")

# Clear counter
print("\nClear counter:")

c = Counter(a=1, b=2, c=3)
print(f"Before: {c}")

c.clear()
print(f"After clear: {c}")

  1. items ← ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']

    5# Basic Counter6print("Basic Counter:")78# Count from list9items→ ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple'] = ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']  #@items=['red', 'blue', 'red'], ['cat', 'dog', 'cat', 'cat']10counter→ Counter({'apple': 3, 'banana': 2, 'cherry': 1}) = Counter(items['apple', 'banana', 'apple', 'cherry', 'banana', 'apple'])1112print(f"Items: {items['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']}")13print(f"Counter: {counterCounter({'apple': 3, 'banana': 2, 'cherry': 1})}")14print(f"apple: {counter['apple']3}")15print(f"banana: {counter['banana']2}")16print(f"grape: {counter['grape']0}")  # Returns 0, not KeyError1718# Count from string19print("\nCount from string:")2021text→ hello world = "hello world"22char_count→ Counter({'l': 3, 'o': 2, 'h': 1, 'e': 1, ' ': 1, 'w': 1, 'r': 1, 'd': 1}) = Counter(texthello world)2324print(f"Text: '{texthello world}'")25print(f"Characters: {char_countCounter({'l': 3, 'o': 2, 'h': 1, 'e': 1, ' ': 1, 'w': 1, 'r': 1, 'd': 1})}")26print(f"'l': {char_count['l']3}")27print(f"'o': {char_count['o']2}")2829# Most common30print("\nMost common:")3132words→ ['the', 'quick', 'brown', 'fox', 'the', 'lazy', 'dog', 'the', 'quick'] = ['the', 'quick', 'brown', 'fox', 'the', 'lazy', 'dog', 'the', 'quick']33word_count→ Counter({'the': 3, 'quick': 2, 'brown': 1, 'fox': 1, 'lazy': 1, 'dog': 1}) = Counter(words['the', 'quick', 'brown', 'fox', 'the', 'lazy', 'dog', 'the', 'quick'])3435print(f"Words: {words['the', 'quick', 'brown', 'fox', 'the', 'lazy', 'dog', 'the', 'quick']}")36print(f"Most common 3: {word_countCounter({'the': 3, 'quick': 2, 'brown': 1, 'fox': 1, 'lazy': 1, 'dog': 1}).most_common(3)}")37print(f"All by frequency: {word_countCounter({'the': 3, 'quick': 2, 'brown': 1, 'fox': 1, 'lazy': 1, 'dog': 1}).most_common()}")3839# Count votes40print("\nCount votes:")4142votes→ ['Alice', 'Bob', 'Alice', 'Charlie', 'Alice', 'Bob', 'Alice'] = ['Alice', 'Bob', 'Alice', 'Charlie', 'Alice', 'Bob', 'Alice']43results→ Counter({'Alice': 4, 'Bob': 2, 'Charlie': 1}) = Counter(votes['Alice', 'Bob', 'Alice', 'Charlie', 'Alice', 'Bob', 'Alice'])4445print(f"Votes: {votes['Alice', 'Bob', 'Alice', 'Charlie', 'Alice', 'Bob', 'Alice']}")46for candidate, count in results.most_common():
    outputBasic Counter:
    Items: ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']
    Counter: Counter({'apple': 3, 'banana': 2, 'cherry': 1})
    apple: 3
    banana: 2
    grape: 0
    
    Count from string:
    Text: 'hello world'
    Characters: Counter({'l': 3, 'o': 2, 'h': 1, 'e': 1, ' ': 1, 'w': 1, 'r': 1, 'd': 1})
    'l': 3
    'o': 2
    
    Most common:
    Words: ['the', 'quick', 'brown', 'fox', 'the', 'lazy', 'dog', 'the', 'quick']
    Most common 3: [('the', 3), ('quick', 2), ('brown', 1)]
    All by frequency: [('the', 3), ('quick', 2), ('brown', 1), ('fox', 1), ('lazy', 1), ('dog', 1)]
    
    Count votes:
    Votes: ['Alice', 'Bob', 'Alice', 'Charlie', 'Alice', 'Bob', 'Alice']
  2. for candidate, count in results.most_common():

    pass 1 of 3
    45print(f"Votes: {votes}")46for candidateAlice, count4 in resultsCounter({'Alice': 4, 'Bob': 2, 'Charlie': 1}).most_common():47    print(f"  {candidateAlice}: {count4} votes")
    output  Alice: 4 votes
    All 3 passes — pass 1 is the card above
    passcandidatecount
    1Alice4
    2Bob2
    3Charlie1
  3. winner ← Alice, c1 ← Counter({'a': 1, 'b': 1, 'c': 1}), inventory ← Counter({'apples': 10, 'oranges': 8, 'bananas': 5})

    49winner→ Alice = resultsCounter({'Alice': 4, 'Bob': 2, 'Charlie': 1}).most_common(1)[0][0]50print(f"Winner: {winnerAlice}")5152# Update counter53print("\nUpdate counter:")5455c1→ Counter({'a': 1, 'b': 1, 'c': 1}) = Counter(['a', 'b', 'c'])56print(f"Initial: {c1Counter({'a': 1, 'b': 1, 'c': 1})}")5758c1→ Counter({'a': 2, 'b': 2, 'c': 1, 'd': 1}).update(['a', 'b', 'd'])59print(f"After update: {c1Counter({'a': 2, 'b': 2, 'c': 1, 'd': 1})}")6061c1→ Counter({'a': 4, 'e': 3, 'b': 2, 'c': 1, 'd': 1}).update({'a': 2, 'e': 3})62print(f"After dict update: {c1Counter({'a': 4, 'e': 3, 'b': 2, 'c': 1, 'd': 1})}")6364# Subtract65print("\nSubtract:")6667inventory→ Counter({'apples': 10, 'oranges': 8, 'bananas': 5}) = Counter(apples=10, bananas=5, oranges=8)68sold→ Counter({'apples': 3, 'bananas': 2, 'oranges': 1}) = Counter(apples=3, bananas=2, oranges=1)6970print(f"Inventory: {inventoryCounter({'apples': 10, 'oranges': 8, 'bananas': 5})}")71print(f"Sold: {soldCounter({'apples': 3, 'bananas': 2, 'oranges': 1})}")7273inventory→ Counter({'apples': 7, 'oranges': 7, 'bananas': 3}).subtract(soldCounter({'apples': 3, 'bananas': 2, 'oranges': 1}))74print(f"Remaining: {inventoryCounter({'apples': 7, 'oranges': 7, 'bananas': 3})}")7576# Counter arithmetic77print("\nCounter arithmetic:")7879c1→ Counter({'a': 3, 'b': 2, 'c': 1}) = Counter(a=3, b=2, c=1)80c2→ Counter({'d': 3, 'b': 2, 'a': 1}) = Counter(a=1, b=2, d=3)8182print(f"C1: {c1Counter({'a': 3, 'b': 2, 'c': 1})}")83print(f"C2: {c2Counter({'d': 3, 'b': 2, 'a': 1})}")84print(f"C1 + C2: {c1Counter({'a': 3, 'b': 2, 'c': 1}) + c2Counter({'d': 3, 'b': 2, 'a': 1})}")85print(f"C1 - C2: {c1Counter({'a': 3, 'b': 2, 'c': 1}) - c2Counter({'d': 3, 'b': 2, 'a': 1})}")86print(f"C1 & C2 (intersection): {c1Counter({'a': 3, 'b': 2, 'c': 1}) & c2Counter({'d': 3, 'b': 2, 'a': 1})}")87print(f"C1 | C2 (union): {c1Counter({'a': 3, 'b': 2, 'c': 1}) | c2Counter({'d': 3, 'b': 2, 'a': 1})}")8889# Elements90print("\nElements:")9192c→ Counter({'a': 3, 'b': 2, 'c': 1}) = Counter(a=3, b=2, c=1)93print(f"Counter: {cCounter({'a': 3, 'b': 2, 'c': 1})}")94print(f"Elements: {list(cCounter({'a': 3, 'b': 2, 'c': 1}).elements())}")9596# Sorted97print(f"Sorted: {sorted(cCounter({'a': 3, 'b': 2, 'c': 1}).elements())}")9899# Total count100print("\nTotal count:")101102inventory→ Counter({'apples': 10, 'oranges': 8, 'bananas': 5}) = Counter(apples=10, bananas=5, oranges=8)103print(f"Inventory: {inventoryCounter({'apples': 10, 'oranges': 8, 'bananas': 5})}")104print(f"Total items: {sum(inventoryCounter({'apples': 10, 'oranges': 8, 'bananas': 5}).values())}")105106# Or use total() in Python 3.10+107# print(f"Total: {inventory.total()}")108109# Most common letter110print("\nMost common letter:")111112text→ the quick brown fox jumps over the lazy dog = "the quick brown fox jumps over the lazy dog"113letters→ Counter({'o': 4, 'e': 3, 't': 2, 'h': 2, 'u': 2, 'r': 2, 'q': 1, 'i': 1, 'c': 1, 'k': 1, 'b': 1, 'w': 1, 'n': 1, 'f': 1, 'x': 1, 'j': 1, 'm': 1, 'p': 1, 's': 1, 'v': 1, 'l': 1, 'a': 1, 'z': 1, 'y': 1, 'd': 1, 'g': 1}) = Counter(c for c in textthe quick brown fox jumps over the lazy dog.lower() if c.isalpha())114115print(f"Text: '{textthe quick brown fox jumps over the lazy dog}'")116print(f"Most common 5 letters: {lettersCounter({'o': 4, 'e': 3, 't': 2, 'h': 2, 'u': 2, 'r': 2, 'q': 1, 'i': 1, 'c': 1, 'k': 1, 'b': 1, 'w': 1, 'n': 1, 'f': 1, 'x': 1, 'j': 1, 'm': 1, 'p': 1, 's': 1, 'v': 1, 'l': 1, 'a': 1, 'z': 1, 'y': 1, 'd': 1, 'g': 1}).most_common(5)}")117118# Word frequency119print("\nWord frequency:")120121document→ the cat and the dog and the bird = "the cat and the dog and the bird"122words→ ['the', 'cat', 'and', 'the', 'dog', 'and', 'the', 'bird'] = documentthe cat and the dog and the bird.split()123freq→ Counter({'the': 3, 'and': 2, 'cat': 1, 'dog': 1, 'bird': 1}) = Counter(words['the', 'cat', 'and', 'the', 'dog', 'and', 'the', 'bird'])124125print(f"Document: '{documentthe cat and the dog and the bird}'")126for word, count in sorted(freq.items(), key=lambda x: x[1], reverse=True):
    outputWinner: Alice
    
    Update counter:
    Initial: Counter({'a': 1, 'b': 1, 'c': 1})
    After update: Counter({'a': 2, 'b': 2, 'c': 1, 'd': 1})
    After dict update: Counter({'a': 4, 'e': 3, 'b': 2, 'c': 1, 'd': 1})
    
    Subtract:
    Inventory: Counter({'apples': 10, 'oranges': 8, 'bananas': 5})
    Sold: Counter({'apples': 3, 'bananas': 2, 'oranges': 1})
    Remaining: Counter({'apples': 7, 'oranges': 7, 'bananas': 3})
    
    Counter arithmetic:
    C1: Counter({'a': 3, 'b': 2, 'c': 1})
    C2: Counter({'d': 3, 'b': 2, 'a': 1})
    C1 + C2: Counter({'a': 4, 'b': 4, 'd': 3, 'c': 1})
    C1 - C2: Counter({'a': 2, 'c': 1})
    C1 & C2 (intersection): Counter({'b': 2, 'a': 1})
    C1 | C2 (union): Counter({'a': 3, 'd': 3, 'b': 2, 'c': 1})
    
    Elements:
    Counter: Counter({'a': 3, 'b': 2, 'c': 1})
    Elements: ['a', 'a', 'a', 'b', 'b', 'c']
    Sorted: ['a', 'a', 'a', 'b', 'b', 'c']
    
    Total count:
    Inventory: Counter({'apples': 10, 'oranges': 8, 'bananas': 5})
    Total items: 23
    
    Most common letter:
    Text: 'the quick brown fox jumps over the lazy dog'
    Most common 5 letters: [('o', 4), ('e', 3), ('t', 2), ('h', 2), ('u', 2)]
    
    Word frequency:
    Document: 'the cat and the dog and the bird'
  4. for word, count in sorted(freq.items(), key=lambda x: x[1], reverse=Tr…

    pass 1 of 5
    125print(f"Document: '{document}'")126for wordthe, count3 in sorted(freqCounter({'the': 3, 'and': 2, 'cat': 1, 'dog': 1, 'bird': 1}).items(), key=lambda x: x[1], reverse=True):127    print(f"  '{wordthe}': {count3}")
    output  'the': 3
    All 5 passes — pass 1 is the card above
    passwordcount
    1the3
    2and2
    3cat1
    4dog1
    5bird1
  5. c ← Counter({'c': 3, 'b': 2, 'a': 1})

    129# Clear counter130print("\nClear counter:")131132c→ Counter({'c': 3, 'b': 2, 'a': 1}) = Counter(a=1, b=2, c=3)133print(f"Before: {cCounter({'c': 3, 'b': 2, 'a': 1})}")134135c→ Counter().clear()136print(f"After clear: {cCounter()}")
    output
    Clear counter:
    Before: Counter({'c': 3, 'b': 2, 'a': 1})
    After clear: Counter()
  1. items ← ['red', 'blue', 'red'], counter ← Counter({'red': 2, 'blue': 1})

    5# Basic Counter6print("Basic Counter:")78# Count from list9items→ ['red', 'blue', 'red'] = ['red', 'blue', 'red']10counter→ Counter({'red': 2, 'blue': 1}) = Counter(items['red', 'blue', 'red'])1112print(f"Items: {items['red', 'blue', 'red']}")13print(f"Counter: {counterCounter({'red': 2, 'blue': 1})}")14print(f"apple: {counter['apple']0}")15print(f"banana: {counter['banana']0}")16print(f"grape: {counter['grape']0}")  # Returns 0, not KeyError1718# Count from string19print("\nCount from string:")2021text→ hello world = "hello world"22char_count→ Counter({'l': 3, 'o': 2, 'h': 1, 'e': 1, ' ': 1, 'w': 1, 'r': 1, 'd': 1}) = Counter(texthello world)2324print(f"Text: '{texthello world}'")25print(f"Characters: {char_countCounter({'l': 3, 'o': 2, 'h': 1, 'e': 1, ' ': 1, 'w': 1, 'r': 1, 'd': 1})}")26print(f"'l': {char_count['l']3}")27print(f"'o': {char_count['o']2}")2829# Most common30print("\nMost common:")3132words→ ['the', 'quick', 'brown', 'fox', 'the', 'lazy', 'dog', 'the', 'quick'] = ['the', 'quick', 'brown', 'fox', 'the', 'lazy', 'dog', 'the', 'quick']33word_count→ Counter({'the': 3, 'quick': 2, 'brown': 1, 'fox': 1, 'lazy': 1, 'dog': 1}) = Counter(words['the', 'quick', 'brown', 'fox', 'the', 'lazy', 'dog', 'the', 'quick'])3435print(f"Words: {words['the', 'quick', 'brown', 'fox', 'the', 'lazy', 'dog', 'the', 'quick']}")36print(f"Most common 3: {word_countCounter({'the': 3, 'quick': 2, 'brown': 1, 'fox': 1, 'lazy': 1, 'dog': 1}).most_common(3)}")37print(f"All by frequency: {word_countCounter({'the': 3, 'quick': 2, 'brown': 1, 'fox': 1, 'lazy': 1, 'dog': 1}).most_common()}")3839# Count votes40print("\nCount votes:")4142votes→ ['Alice', 'Bob', 'Alice', 'Charlie', 'Alice', 'Bob', 'Alice'] = ['Alice', 'Bob', 'Alice', 'Charlie', 'Alice', 'Bob', 'Alice']43results→ Counter({'Alice': 4, 'Bob': 2, 'Charlie': 1}) = Counter(votes['Alice', 'Bob', 'Alice', 'Charlie', 'Alice', 'Bob', 'Alice'])4445print(f"Votes: {votes['Alice', 'Bob', 'Alice', 'Charlie', 'Alice', 'Bob', 'Alice']}")46for candidate, count in results.most_common():
    outputBasic Counter:
    Items: ['red', 'blue', 'red']
    Counter: Counter({'red': 2, 'blue': 1})
    apple: 0
    banana: 0
    grape: 0
    
    Count from string:
    Text: 'hello world'
    Characters: Counter({'l': 3, 'o': 2, 'h': 1, 'e': 1, ' ': 1, 'w': 1, 'r': 1, 'd': 1})
    'l': 3
    'o': 2
    
    Most common:
    Words: ['the', 'quick', 'brown', 'fox', 'the', 'lazy', 'dog', 'the', 'quick']
    Most common 3: [('the', 3), ('quick', 2), ('brown', 1)]
    All by frequency: [('the', 3), ('quick', 2), ('brown', 1), ('fox', 1), ('lazy', 1), ('dog', 1)]
    
    Count votes:
    Votes: ['Alice', 'Bob', 'Alice', 'Charlie', 'Alice', 'Bob', 'Alice']
  2. for candidate, count in results.most_common():

    pass 1 of 3
    45print(f"Votes: {votes}")46for candidateAlice, count4 in resultsCounter({'Alice': 4, 'Bob': 2, 'Charlie': 1}).most_common():47    print(f"  {candidateAlice}: {count4} votes")
    output  Alice: 4 votes
    All 3 passes — pass 1 is the card above
    passcandidatecount
    1Alice4
    2Bob2
    3Charlie1
  3. winner ← Alice, c1 ← Counter({'a': 1, 'b': 1, 'c': 1}), inventory ← Counter({'apples': 10, 'oranges': 8, 'bananas': 5})

    49winner→ Alice = resultsCounter({'Alice': 4, 'Bob': 2, 'Charlie': 1}).most_common(1)[0][0]50print(f"Winner: {winnerAlice}")5152# Update counter53print("\nUpdate counter:")5455c1→ Counter({'a': 1, 'b': 1, 'c': 1}) = Counter(['a', 'b', 'c'])56print(f"Initial: {c1Counter({'a': 1, 'b': 1, 'c': 1})}")5758c1→ Counter({'a': 2, 'b': 2, 'c': 1, 'd': 1}).update(['a', 'b', 'd'])59print(f"After update: {c1Counter({'a': 2, 'b': 2, 'c': 1, 'd': 1})}")6061c1→ Counter({'a': 4, 'e': 3, 'b': 2, 'c': 1, 'd': 1}).update({'a': 2, 'e': 3})62print(f"After dict update: {c1Counter({'a': 4, 'e': 3, 'b': 2, 'c': 1, 'd': 1})}")6364# Subtract65print("\nSubtract:")6667inventory→ Counter({'apples': 10, 'oranges': 8, 'bananas': 5}) = Counter(apples=10, bananas=5, oranges=8)68sold→ Counter({'apples': 3, 'bananas': 2, 'oranges': 1}) = Counter(apples=3, bananas=2, oranges=1)6970print(f"Inventory: {inventoryCounter({'apples': 10, 'oranges': 8, 'bananas': 5})}")71print(f"Sold: {soldCounter({'apples': 3, 'bananas': 2, 'oranges': 1})}")7273inventory→ Counter({'apples': 7, 'oranges': 7, 'bananas': 3}).subtract(soldCounter({'apples': 3, 'bananas': 2, 'oranges': 1}))74print(f"Remaining: {inventoryCounter({'apples': 7, 'oranges': 7, 'bananas': 3})}")7576# Counter arithmetic77print("\nCounter arithmetic:")7879c1→ Counter({'a': 3, 'b': 2, 'c': 1}) = Counter(a=3, b=2, c=1)80c2→ Counter({'d': 3, 'b': 2, 'a': 1}) = Counter(a=1, b=2, d=3)8182print(f"C1: {c1Counter({'a': 3, 'b': 2, 'c': 1})}")83print(f"C2: {c2Counter({'d': 3, 'b': 2, 'a': 1})}")84print(f"C1 + C2: {c1Counter({'a': 3, 'b': 2, 'c': 1}) + c2Counter({'d': 3, 'b': 2, 'a': 1})}")85print(f"C1 - C2: {c1Counter({'a': 3, 'b': 2, 'c': 1}) - c2Counter({'d': 3, 'b': 2, 'a': 1})}")86print(f"C1 & C2 (intersection): {c1Counter({'a': 3, 'b': 2, 'c': 1}) & c2Counter({'d': 3, 'b': 2, 'a': 1})}")87print(f"C1 | C2 (union): {c1Counter({'a': 3, 'b': 2, 'c': 1}) | c2Counter({'d': 3, 'b': 2, 'a': 1})}")8889# Elements90print("\nElements:")9192c→ Counter({'a': 3, 'b': 2, 'c': 1}) = Counter(a=3, b=2, c=1)93print(f"Counter: {cCounter({'a': 3, 'b': 2, 'c': 1})}")94print(f"Elements: {list(cCounter({'a': 3, 'b': 2, 'c': 1}).elements())}")9596# Sorted97print(f"Sorted: {sorted(cCounter({'a': 3, 'b': 2, 'c': 1}).elements())}")9899# Total count100print("\nTotal count:")101102inventory→ Counter({'apples': 10, 'oranges': 8, 'bananas': 5}) = Counter(apples=10, bananas=5, oranges=8)103print(f"Inventory: {inventoryCounter({'apples': 10, 'oranges': 8, 'bananas': 5})}")104print(f"Total items: {sum(inventoryCounter({'apples': 10, 'oranges': 8, 'bananas': 5}).values())}")105106# Or use total() in Python 3.10+107# print(f"Total: {inventory.total()}")108109# Most common letter110print("\nMost common letter:")111112text→ the quick brown fox jumps over the lazy dog = "the quick brown fox jumps over the lazy dog"113letters→ Counter({'o': 4, 'e': 3, 't': 2, 'h': 2, 'u': 2, 'r': 2, 'q': 1, 'i': 1, 'c': 1, 'k': 1, 'b': 1, 'w': 1, 'n': 1, 'f': 1, 'x': 1, 'j': 1, 'm': 1, 'p': 1, 's': 1, 'v': 1, 'l': 1, 'a': 1, 'z': 1, 'y': 1, 'd': 1, 'g': 1}) = Counter(c for c in textthe quick brown fox jumps over the lazy dog.lower() if c.isalpha())114115print(f"Text: '{textthe quick brown fox jumps over the lazy dog}'")116print(f"Most common 5 letters: {lettersCounter({'o': 4, 'e': 3, 't': 2, 'h': 2, 'u': 2, 'r': 2, 'q': 1, 'i': 1, 'c': 1, 'k': 1, 'b': 1, 'w': 1, 'n': 1, 'f': 1, 'x': 1, 'j': 1, 'm': 1, 'p': 1, 's': 1, 'v': 1, 'l': 1, 'a': 1, 'z': 1, 'y': 1, 'd': 1, 'g': 1}).most_common(5)}")117118# Word frequency119print("\nWord frequency:")120121document→ the cat and the dog and the bird = "the cat and the dog and the bird"122words→ ['the', 'cat', 'and', 'the', 'dog', 'and', 'the', 'bird'] = documentthe cat and the dog and the bird.split()123freq→ Counter({'the': 3, 'and': 2, 'cat': 1, 'dog': 1, 'bird': 1}) = Counter(words['the', 'cat', 'and', 'the', 'dog', 'and', 'the', 'bird'])124125print(f"Document: '{documentthe cat and the dog and the bird}'")126for word, count in sorted(freq.items(), key=lambda x: x[1], reverse=True):
    outputWinner: Alice
    
    Update counter:
    Initial: Counter({'a': 1, 'b': 1, 'c': 1})
    After update: Counter({'a': 2, 'b': 2, 'c': 1, 'd': 1})
    After dict update: Counter({'a': 4, 'e': 3, 'b': 2, 'c': 1, 'd': 1})
    
    Subtract:
    Inventory: Counter({'apples': 10, 'oranges': 8, 'bananas': 5})
    Sold: Counter({'apples': 3, 'bananas': 2, 'oranges': 1})
    Remaining: Counter({'apples': 7, 'oranges': 7, 'bananas': 3})
    
    Counter arithmetic:
    C1: Counter({'a': 3, 'b': 2, 'c': 1})
    C2: Counter({'d': 3, 'b': 2, 'a': 1})
    C1 + C2: Counter({'a': 4, 'b': 4, 'd': 3, 'c': 1})
    C1 - C2: Counter({'a': 2, 'c': 1})
    C1 & C2 (intersection): Counter({'b': 2, 'a': 1})
    C1 | C2 (union): Counter({'a': 3, 'd': 3, 'b': 2, 'c': 1})
    
    Elements:
    Counter: Counter({'a': 3, 'b': 2, 'c': 1})
    Elements: ['a', 'a', 'a', 'b', 'b', 'c']
    Sorted: ['a', 'a', 'a', 'b', 'b', 'c']
    
    Total count:
    Inventory: Counter({'apples': 10, 'oranges': 8, 'bananas': 5})
    Total items: 23
    
    Most common letter:
    Text: 'the quick brown fox jumps over the lazy dog'
    Most common 5 letters: [('o', 4), ('e', 3), ('t', 2), ('h', 2), ('u', 2)]
    
    Word frequency:
    Document: 'the cat and the dog and the bird'
  4. for word, count in sorted(freq.items(), key=lambda x: x[1], reverse=Tr…

    pass 1 of 5
    125print(f"Document: '{document}'")126for wordthe, count3 in sorted(freqCounter({'the': 3, 'and': 2, 'cat': 1, 'dog': 1, 'bird': 1}).items(), key=lambda x: x[1], reverse=True):127    print(f"  '{wordthe}': {count3}")
    output  'the': 3
    All 5 passes — pass 1 is the card above
    passwordcount
    1the3
    2and2
    3cat1
    4dog1
    5bird1
  5. c ← Counter({'c': 3, 'b': 2, 'a': 1})

    129# Clear counter130print("\nClear counter:")131132c→ Counter({'c': 3, 'b': 2, 'a': 1}) = Counter(a=1, b=2, c=3)133print(f"Before: {cCounter({'c': 3, 'b': 2, 'a': 1})}")134135c→ Counter().clear()136print(f"After clear: {cCounter()}")
    output
    Clear counter:
    Before: Counter({'c': 3, 'b': 2, 'a': 1})
    After clear: Counter()
  1. items ← ['cat', 'dog', 'cat', 'cat'], counter ← Counter({'cat': 3, 'dog': 1})

    5# Basic Counter6print("Basic Counter:")78# Count from list9items→ ['cat', 'dog', 'cat', 'cat'] = ['cat', 'dog', 'cat', 'cat']10counter→ Counter({'cat': 3, 'dog': 1}) = Counter(items['cat', 'dog', 'cat', 'cat'])1112print(f"Items: {items['cat', 'dog', 'cat', 'cat']}")13print(f"Counter: {counterCounter({'cat': 3, 'dog': 1})}")14print(f"apple: {counter['apple']0}")15print(f"banana: {counter['banana']0}")16print(f"grape: {counter['grape']0}")  # Returns 0, not KeyError1718# Count from string19print("\nCount from string:")2021text→ hello world = "hello world"22char_count→ Counter({'l': 3, 'o': 2, 'h': 1, 'e': 1, ' ': 1, 'w': 1, 'r': 1, 'd': 1}) = Counter(texthello world)2324print(f"Text: '{texthello world}'")25print(f"Characters: {char_countCounter({'l': 3, 'o': 2, 'h': 1, 'e': 1, ' ': 1, 'w': 1, 'r': 1, 'd': 1})}")26print(f"'l': {char_count['l']3}")27print(f"'o': {char_count['o']2}")2829# Most common30print("\nMost common:")3132words→ ['the', 'quick', 'brown', 'fox', 'the', 'lazy', 'dog', 'the', 'quick'] = ['the', 'quick', 'brown', 'fox', 'the', 'lazy', 'dog', 'the', 'quick']33word_count→ Counter({'the': 3, 'quick': 2, 'brown': 1, 'fox': 1, 'lazy': 1, 'dog': 1}) = Counter(words['the', 'quick', 'brown', 'fox', 'the', 'lazy', 'dog', 'the', 'quick'])3435print(f"Words: {words['the', 'quick', 'brown', 'fox', 'the', 'lazy', 'dog', 'the', 'quick']}")36print(f"Most common 3: {word_countCounter({'the': 3, 'quick': 2, 'brown': 1, 'fox': 1, 'lazy': 1, 'dog': 1}).most_common(3)}")37print(f"All by frequency: {word_countCounter({'the': 3, 'quick': 2, 'brown': 1, 'fox': 1, 'lazy': 1, 'dog': 1}).most_common()}")3839# Count votes40print("\nCount votes:")4142votes→ ['Alice', 'Bob', 'Alice', 'Charlie', 'Alice', 'Bob', 'Alice'] = ['Alice', 'Bob', 'Alice', 'Charlie', 'Alice', 'Bob', 'Alice']43results→ Counter({'Alice': 4, 'Bob': 2, 'Charlie': 1}) = Counter(votes['Alice', 'Bob', 'Alice', 'Charlie', 'Alice', 'Bob', 'Alice'])4445print(f"Votes: {votes['Alice', 'Bob', 'Alice', 'Charlie', 'Alice', 'Bob', 'Alice']}")46for candidate, count in results.most_common():
    outputBasic Counter:
    Items: ['cat', 'dog', 'cat', 'cat']
    Counter: Counter({'cat': 3, 'dog': 1})
    apple: 0
    banana: 0
    grape: 0
    
    Count from string:
    Text: 'hello world'
    Characters: Counter({'l': 3, 'o': 2, 'h': 1, 'e': 1, ' ': 1, 'w': 1, 'r': 1, 'd': 1})
    'l': 3
    'o': 2
    
    Most common:
    Words: ['the', 'quick', 'brown', 'fox', 'the', 'lazy', 'dog', 'the', 'quick']
    Most common 3: [('the', 3), ('quick', 2), ('brown', 1)]
    All by frequency: [('the', 3), ('quick', 2), ('brown', 1), ('fox', 1), ('lazy', 1), ('dog', 1)]
    
    Count votes:
    Votes: ['Alice', 'Bob', 'Alice', 'Charlie', 'Alice', 'Bob', 'Alice']
  2. for candidate, count in results.most_common():

    pass 1 of 3
    45print(f"Votes: {votes}")46for candidateAlice, count4 in resultsCounter({'Alice': 4, 'Bob': 2, 'Charlie': 1}).most_common():47    print(f"  {candidateAlice}: {count4} votes")
    output  Alice: 4 votes
    All 3 passes — pass 1 is the card above
    passcandidatecount
    1Alice4
    2Bob2
    3Charlie1
  3. winner ← Alice, c1 ← Counter({'a': 1, 'b': 1, 'c': 1}), inventory ← Counter({'apples': 10, 'oranges': 8, 'bananas': 5})

    49winner→ Alice = resultsCounter({'Alice': 4, 'Bob': 2, 'Charlie': 1}).most_common(1)[0][0]50print(f"Winner: {winnerAlice}")5152# Update counter53print("\nUpdate counter:")5455c1→ Counter({'a': 1, 'b': 1, 'c': 1}) = Counter(['a', 'b', 'c'])56print(f"Initial: {c1Counter({'a': 1, 'b': 1, 'c': 1})}")5758c1→ Counter({'a': 2, 'b': 2, 'c': 1, 'd': 1}).update(['a', 'b', 'd'])59print(f"After update: {c1Counter({'a': 2, 'b': 2, 'c': 1, 'd': 1})}")6061c1→ Counter({'a': 4, 'e': 3, 'b': 2, 'c': 1, 'd': 1}).update({'a': 2, 'e': 3})62print(f"After dict update: {c1Counter({'a': 4, 'e': 3, 'b': 2, 'c': 1, 'd': 1})}")6364# Subtract65print("\nSubtract:")6667inventory→ Counter({'apples': 10, 'oranges': 8, 'bananas': 5}) = Counter(apples=10, bananas=5, oranges=8)68sold→ Counter({'apples': 3, 'bananas': 2, 'oranges': 1}) = Counter(apples=3, bananas=2, oranges=1)6970print(f"Inventory: {inventoryCounter({'apples': 10, 'oranges': 8, 'bananas': 5})}")71print(f"Sold: {soldCounter({'apples': 3, 'bananas': 2, 'oranges': 1})}")7273inventory→ Counter({'apples': 7, 'oranges': 7, 'bananas': 3}).subtract(soldCounter({'apples': 3, 'bananas': 2, 'oranges': 1}))74print(f"Remaining: {inventoryCounter({'apples': 7, 'oranges': 7, 'bananas': 3})}")7576# Counter arithmetic77print("\nCounter arithmetic:")7879c1→ Counter({'a': 3, 'b': 2, 'c': 1}) = Counter(a=3, b=2, c=1)80c2→ Counter({'d': 3, 'b': 2, 'a': 1}) = Counter(a=1, b=2, d=3)8182print(f"C1: {c1Counter({'a': 3, 'b': 2, 'c': 1})}")83print(f"C2: {c2Counter({'d': 3, 'b': 2, 'a': 1})}")84print(f"C1 + C2: {c1Counter({'a': 3, 'b': 2, 'c': 1}) + c2Counter({'d': 3, 'b': 2, 'a': 1})}")85print(f"C1 - C2: {c1Counter({'a': 3, 'b': 2, 'c': 1}) - c2Counter({'d': 3, 'b': 2, 'a': 1})}")86print(f"C1 & C2 (intersection): {c1Counter({'a': 3, 'b': 2, 'c': 1}) & c2Counter({'d': 3, 'b': 2, 'a': 1})}")87print(f"C1 | C2 (union): {c1Counter({'a': 3, 'b': 2, 'c': 1}) | c2Counter({'d': 3, 'b': 2, 'a': 1})}")8889# Elements90print("\nElements:")9192c→ Counter({'a': 3, 'b': 2, 'c': 1}) = Counter(a=3, b=2, c=1)93print(f"Counter: {cCounter({'a': 3, 'b': 2, 'c': 1})}")94print(f"Elements: {list(cCounter({'a': 3, 'b': 2, 'c': 1}).elements())}")9596# Sorted97print(f"Sorted: {sorted(cCounter({'a': 3, 'b': 2, 'c': 1}).elements())}")9899# Total count100print("\nTotal count:")101102inventory→ Counter({'apples': 10, 'oranges': 8, 'bananas': 5}) = Counter(apples=10, bananas=5, oranges=8)103print(f"Inventory: {inventoryCounter({'apples': 10, 'oranges': 8, 'bananas': 5})}")104print(f"Total items: {sum(inventoryCounter({'apples': 10, 'oranges': 8, 'bananas': 5}).values())}")105106# Or use total() in Python 3.10+107# print(f"Total: {inventory.total()}")108109# Most common letter110print("\nMost common letter:")111112text→ the quick brown fox jumps over the lazy dog = "the quick brown fox jumps over the lazy dog"113letters→ Counter({'o': 4, 'e': 3, 't': 2, 'h': 2, 'u': 2, 'r': 2, 'q': 1, 'i': 1, 'c': 1, 'k': 1, 'b': 1, 'w': 1, 'n': 1, 'f': 1, 'x': 1, 'j': 1, 'm': 1, 'p': 1, 's': 1, 'v': 1, 'l': 1, 'a': 1, 'z': 1, 'y': 1, 'd': 1, 'g': 1}) = Counter(c for c in textthe quick brown fox jumps over the lazy dog.lower() if c.isalpha())114115print(f"Text: '{textthe quick brown fox jumps over the lazy dog}'")116print(f"Most common 5 letters: {lettersCounter({'o': 4, 'e': 3, 't': 2, 'h': 2, 'u': 2, 'r': 2, 'q': 1, 'i': 1, 'c': 1, 'k': 1, 'b': 1, 'w': 1, 'n': 1, 'f': 1, 'x': 1, 'j': 1, 'm': 1, 'p': 1, 's': 1, 'v': 1, 'l': 1, 'a': 1, 'z': 1, 'y': 1, 'd': 1, 'g': 1}).most_common(5)}")117118# Word frequency119print("\nWord frequency:")120121document→ the cat and the dog and the bird = "the cat and the dog and the bird"122words→ ['the', 'cat', 'and', 'the', 'dog', 'and', 'the', 'bird'] = documentthe cat and the dog and the bird.split()123freq→ Counter({'the': 3, 'and': 2, 'cat': 1, 'dog': 1, 'bird': 1}) = Counter(words['the', 'cat', 'and', 'the', 'dog', 'and', 'the', 'bird'])124125print(f"Document: '{documentthe cat and the dog and the bird}'")126for word, count in sorted(freq.items(), key=lambda x: x[1], reverse=True):
    outputWinner: Alice
    
    Update counter:
    Initial: Counter({'a': 1, 'b': 1, 'c': 1})
    After update: Counter({'a': 2, 'b': 2, 'c': 1, 'd': 1})
    After dict update: Counter({'a': 4, 'e': 3, 'b': 2, 'c': 1, 'd': 1})
    
    Subtract:
    Inventory: Counter({'apples': 10, 'oranges': 8, 'bananas': 5})
    Sold: Counter({'apples': 3, 'bananas': 2, 'oranges': 1})
    Remaining: Counter({'apples': 7, 'oranges': 7, 'bananas': 3})
    
    Counter arithmetic:
    C1: Counter({'a': 3, 'b': 2, 'c': 1})
    C2: Counter({'d': 3, 'b': 2, 'a': 1})
    C1 + C2: Counter({'a': 4, 'b': 4, 'd': 3, 'c': 1})
    C1 - C2: Counter({'a': 2, 'c': 1})
    C1 & C2 (intersection): Counter({'b': 2, 'a': 1})
    C1 | C2 (union): Counter({'a': 3, 'd': 3, 'b': 2, 'c': 1})
    
    Elements:
    Counter: Counter({'a': 3, 'b': 2, 'c': 1})
    Elements: ['a', 'a', 'a', 'b', 'b', 'c']
    Sorted: ['a', 'a', 'a', 'b', 'b', 'c']
    
    Total count:
    Inventory: Counter({'apples': 10, 'oranges': 8, 'bananas': 5})
    Total items: 23
    
    Most common letter:
    Text: 'the quick brown fox jumps over the lazy dog'
    Most common 5 letters: [('o', 4), ('e', 3), ('t', 2), ('h', 2), ('u', 2)]
    
    Word frequency:
    Document: 'the cat and the dog and the bird'
  4. for word, count in sorted(freq.items(), key=lambda x: x[1], reverse=Tr…

    pass 1 of 5
    125print(f"Document: '{document}'")126for wordthe, count3 in sorted(freqCounter({'the': 3, 'and': 2, 'cat': 1, 'dog': 1, 'bird': 1}).items(), key=lambda x: x[1], reverse=True):127    print(f"  '{wordthe}': {count3}")
    output  'the': 3
    All 5 passes — pass 1 is the card above
    passwordcount
    1the3
    2and2
    3cat1
    4dog1
    5bird1
  5. c ← Counter({'c': 3, 'b': 2, 'a': 1})

    129# Clear counter130print("\nClear counter:")131132c→ Counter({'c': 3, 'b': 2, 'a': 1}) = Counter(a=1, b=2, c=3)133print(f"Before: {cCounter({'c': 3, 'b': 2, 'a': 1})}")134135c→ Counter().clear()136print(f"After clear: {cCounter()}")
    output
    Clear counter:
    Before: Counter({'c': 3, 'b': 2, 'a': 1})
    After clear: Counter()
Counter A dict subclass for counting hashable objects - automatically tallies elements and provides methods like most_common() for frequency analysis.

defaultdict

Dictionaries with automatic default values:

defaultdict.py
Replay: real traced execution (multi-file project)
# defaultdict examples

from collections import defaultdict

# Basic defaultdict
print("Basic defaultdict:")

# With list
dd = defaultdict(list)

dd['fruits'].append('apple')
dd['fruits'].append('banana')
dd['vegetables'].append('carrot')

print(f"DefaultDict: {dict(dd)}")
print(f"Fruits: {dd['fruits']}")
print(f"Non-existent: {dd['meats']}")  # Returns []

# With int (counter)
print("\nWith int (counter):")

counts = defaultdict(int)

words = ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']
for word in words:
    counts[word] += 1

print(f"Words: {words}")
print(f"Counts: {dict(counts)}")

# With set
print("\nWith set:")

groups = defaultdict(set)

data = [
    ('Alice', 'Math'),
    ('Bob', 'Science'),
    ('Alice', 'English'),
    ('Charlie', 'Math'),
    ('Bob', 'Math')
]

for student, subject in data:
    groups[student].add(subject)

print("Student subjects:")
for student, subjects in groups.items():
    print(f"  {student}: {subjects}")

# Grouping items
print("\nGrouping items:")

students = [
    {'name': 'Alice', 'grade': 'A'},
    {'name': 'Bob', 'grade': 'B'},
    {'name': 'Charlie', 'grade': 'A'},
    {'name': 'David', 'grade': 'C'},
    {'name': 'Eve', 'grade': 'B'}
]

by_grade = defaultdict(list)
for student in students:
    by_grade[student['grade']].append(student['name'])

print("By grade:")
for grade in sorted(by_grade.keys()):
    print(f"  Grade {grade}: {', '.join(by_grade[grade])}")

# Nested defaultdict
print("\nNested defaultdict:")

# Tree structure
tree = lambda: defaultdict(tree)
users = tree()

users['Alice']['age'] = 30
users['Alice']['city'] = 'NYC'
users['Bob']['age'] = 25
users['Bob']['city'] = 'LA'

print(f"Users: {dict(users)}")
print(f"Alice age: {users['Alice']['age']}")

# Graph representation
print("\nGraph representation:")

graph = defaultdict(list)

edges = [
    ('A', 'B'),
    ('A', 'C'),
    ('B', 'D'),
    ('C', 'D'),
    ('D', 'E')
]

for src, dst in edges:
    graph[src].append(dst)

print("Graph edges:")
for node, neighbors in sorted(graph.items()):
    print(f"  {node} -> {neighbors}")

# Word index
print("\nWord index:")

text = "the quick brown fox jumps over the lazy dog"
word_positions = defaultdict(list)

for i, word in enumerate(text.split()):
    word_positions[word].append(i)

print(f"Text: '{text}'")
print("Word positions:")
for word in sorted(word_positions.keys()):
    print(f"  '{word}': {word_positions[word]}")

# Custom default factory
print("\nCustom default factory:")

def default_value():
    return "N/A"

info = defaultdict(default_value)
info['name'] = 'Alice'
info['age'] = 30

print(f"Name: {info['name']}")
print(f"Age: {info['age']}")
print(f"City: {info['city']}")  # Returns "N/A"

# Matrix representation
print("\nMatrix representation:")

matrix = defaultdict(lambda: defaultdict(int))

matrix[0][0] = 1
matrix[0][2] = 3
matrix[1][1] = 5
matrix[2][0] = 7

print("Sparse matrix:")
for i in range(3):
    row = [matrix[i][j] for j in range(3)]
    print(f"  {row}")

# Convert to regular dict
print("\nConvert to regular dict:")

dd = defaultdict(list)
dd['a'].append(1)
dd['b'].append(2)

print(f"DefaultDict: {dd}")
print(f"Regular dict: {dict(dd)}")

# Access after conversion
regular = dict(dd)
try:
    regular['c'].append(3)
except KeyError:
    print("KeyError on regular dict (expected)")

# Frequency table
print("\nFrequency table:")

data = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
freq = defaultdict(int)

for n in data:
    freq[n] += 1

print(f"Data: {data}")
print("Frequency:")
for num in sorted(freq.keys()):
    bar = '█' * freq[num]
    print(f"  {num}: {bar} ({freq[num]})")

  1. dd ← defaultdict(<class 'list'>, {}), dd[’fruits’] ← ['apple']

    5# Basic defaultdict6print("Basic defaultdict:")78# With list9dd→ defaultdict(<class 'list'>, {}) = defaultdict(list)1011dd['fruits']→ ['apple'].append('apple')12dd['fruits']→ ['apple', 'banana'].append('banana')13dd['vegetables']→ ['carrot'].append('carrot')1415print(f"DefaultDict: {dict(dddefaultdict(<class 'list'>, {'fruits': ['apple', 'banana'], 'vegetables': ['carrot']}))}")16print(f"Fruits: {dd['fruits']['apple', 'banana']}")17print(f"Non-existent: {dd['meats'][]}")  # Returns []1819# With int (counter)20print("\nWith int (counter):")2122counts→ defaultdict(<class 'int'>, {}) = defaultdict(int)2324words→ ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple'] = ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']25for word in words:
    outputBasic defaultdict:
    DefaultDict: {'fruits': ['apple', 'banana'], 'vegetables': ['carrot']}
    Fruits: ['apple', 'banana']
    Non-existent: []
    
    With int (counter):
  2. counts[word] ← 1

    pass 1 of 6
    24words = ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']25for wordapple in words['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']:26    counts[word]→ 1 += 1
    All 6 passes — pass 1 is the card above
    passwordcounts[word]
    1apple0 1
    2banana0 1
    3apple1 2
    4cherry0 1
    5banana1 2
    6apple2 3
  3. groups ← defaultdict(<class 'set'>, {}), data ← [('Alice', 'Math'), ('Bob', 'Science'), ('Alice', 'English'), ('Charlie', 'Math'), ('Bob', 'Math')]

    28print(f"Words: {words['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']}")29print(f"Counts: {dict(countsdefaultdict(<class 'int'>, {'apple': 3, 'banana': 2, 'cherry': 1}))}")3031# With set32print("\nWith set:")3334groups→ defaultdict(<class 'set'>, {}) = defaultdict(set)3536data→ [('Alice', 'Math'), ('Bob', 'Science'), ('Alice', 'English'), ('Charlie', 'Math'), ('Bob', 'Math')] = [37    ('Alice', 'Math'),38    ('Bob', 'Science'),39    ('Alice', 'English'),40    ('Charlie', 'Math'),41    ('Bob', 'Math')42]
    outputWords: ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']
    Counts: {'apple': 3, 'banana': 2, 'cherry': 1}
    
    With set:
  4. groups[student] ← {'Math'}

    pass 1 of 5
    44for studentAlice, subjectMath in data[('Alice', 'Math'), ('Bob', 'Science'), ('Alice', 'English'), ('Charlie', 'Math'), ('Bob', 'Math')]:45    groups[student]→ {'Math'}.add(subjectMath)
    All 5 passes — pass 1 is the card above
    passstudentsubjectgroups[student]
    1AliceMathset() {'Math'}
    2BobScienceset() {'Science'}
    3AliceEnglish{'Math'} {'Math', 'English'}
    4CharlieMathset() {'Math'}
    5BobMath{'Science'} {'Math', 'Science'}
  5. print("Student subjects:")

    47print("Student subjects:")48for student, subjects in groups.items():
    outputStudent subjects:
  6. for student, subjects in groups.items():

    pass 1 of 3
    47print("Student subjects:")48for studentAlice, subjects{'Math', 'English'} in groupsdefaultdict(<class 'set'>, {'Alice': {'Math', 'English'}, 'Bob': {'Math', 'Science'}, 'Charlie': {'Math'}}).items():49    print(f"  {studentAlice}: {subjects{'Math', 'English'}}")
    output  Alice: {'Math', 'English'}
    All 3 passes — pass 1 is the card above
    passstudentsubjects
    1Alice{'Math', 'English'}
    2Bob{'Math', 'Science'}
    3Charlie{'Math'}
  7. students ← [{'name': 'Alice', 'grade': 'A'}, {'name': 'Bob', 'grade': 'B'}, {'name': 'Charlie', 'grade': 'A'}, {'name': 'David', 'grade': 'C'}, {'name': 'Eve', 'grade': 'B'}]

    51# Grouping items52print("\nGrouping items:")5354students→ [{'name': 'Alice', 'grade': 'A'}, {'name': 'Bob', 'grade': 'B'}, {'name': 'Charlie', 'grade': 'A'}, {'name': 'David', 'grade': 'C'}, {'name': 'Eve', 'grade': 'B'}] = [55    {'name': 'Alice', 'grade': 'A'},56    {'name': 'Bob', 'grade': 'B'},57    {'name': 'Charlie', 'grade': 'A'},58    {'name': 'David', 'grade': 'C'},59    {'name': 'Eve', 'grade': 'B'}60]6162by_grade→ defaultdict(<class 'list'>, {}) = defaultdict(list)63for student in students:
    output
    Grouping items:
  8. by_grade[student[’grade’]] ← ['Alice']

    pass 1 of 5
    62by_grade = defaultdict(list)63for student{'name': 'Alice', 'grade': 'A'} in students[{'name': 'Alice', 'grade': 'A'}, {'name': 'Bob', 'grade': 'B'}, {'name': 'Charlie', 'grade': 'A'}, {'name': 'David', 'grade': 'C'}, {'name': 'Eve', 'grade': 'B'}]:64    by_grade[student['grade']]→ ['Alice'].append(student['name']Alice)
    All 5 passes — pass 1 is the card above
    passstudentstudent[’name’]by_grade[student[’grade’]]
    1{'name': 'Alice', 'grade': 'A'}Alice[] ['Alice']
    2{'name': 'Bob', 'grade': 'B'}Bob[] ['Bob']
    3{'name': 'Charlie', 'grade': 'A'}Charlie['Alice'] ['Alice', 'Charlie']
    4{'name': 'David', 'grade': 'C'}David[] ['David']
    5{'name': 'Eve', 'grade': 'B'}Eve['Bob'] ['Bob', 'Eve']
  9. print("By grade:")

    66print("By grade:")67for grade in sorted(by_grade.keys()):
    outputBy grade:
  10. for grade in sorted(by_grade.keys()):

    pass 1 of 3
    66print("By grade:")67for gradeA in sorted(by_gradedefaultdict(<class 'list'>, {'A': ['Alice', 'Charlie'], 'B': ['Bob', 'Eve'], 'C': ['David']}).keys()):68    print(f"  Grade {gradeA}: {', '.join(by_grade[grade]['Alice', 'Charlie'])}")
    output  Grade A: Alice, Charlie
    All 3 passes — pass 1 is the card above
    passgradeby_grade[grade]
    1A['Alice', 'Charlie']
    2B['Bob', 'Eve']
    3C['David']
  11. tree ← <function <lambda> at ⟨addr A⟩>, users ← defaultdict(<function <lambda> at ⟨addr A⟩>, {})

    70# Nested defaultdict71print("\nNested defaultdict:")7273# Tree structure74tree→ <function <lambda> at ⟨addr A⟩> = lambda: defaultdict(tree)75users→ defaultdict(<function <lambda> at ⟨addr A⟩>, {}) = tree()7677users['Alice']['age']→ 30 = 3078users['Alice']['city']→ NYC = 'NYC'79users['Bob']['age']→ 25 = 2580users['Bob']['city']→ LA = 'LA'8182print(f"Users: {dict(usersdefaultdict(<function <lambda> at ⟨addr A⟩>, {'Alice': defaultdict(<function <lambda> at ⟨addr A⟩>, {'age': 30, 'city': 'NYC'}), 'Bob': defaultdict(<function <lambda> at ⟨addr A⟩>, {'age': 25, 'city': 'LA'})}))}")83print(f"Alice age: {users['Alice']['age']30}")8485# Graph representation86print("\nGraph representation:")8788graph→ defaultdict(<class 'list'>, {}) = defaultdict(list)8990edges→ [('A', 'B'), ('A', 'C'), ('B', 'D'), ('C', 'D'), ('D', 'E')] = [91    ('A', 'B'),92    ('A', 'C'),93    ('B', 'D'),94    ('C', 'D'),95    ('D', 'E')96]
    output
    Nested defaultdict:
    Users: {'Alice': defaultdict(<function <lambda> at ⟨addr A⟩>, {'age': 30, 'city': 'NYC'}), 'Bob': defaultdict(<function <lambda> at ⟨addr A⟩>, {'age': 25, 'city': 'LA'})}
    Alice age: 30
    
    Graph representation:
  12. graph[src] ← ['B']

    pass 1 of 5
    98for srcA, dstB in edges[('A', 'B'), ('A', 'C'), ('B', 'D'), ('C', 'D'), ('D', 'E')]:99    graph[src]→ ['B'].append(dstB)
    All 5 passes — pass 1 is the card above
    passsrcdstgraph[src]
    1AB[] ['B']
    2AC['B'] ['B', 'C']
    3BD[] ['D']
    4CD[] ['D']
    5DE[] ['E']
  13. print("Graph edges:")

    101print("Graph edges:")102for node, neighbors in sorted(graph.items()):
    outputGraph edges:
  14. for node, neighbors in sorted(graph.items()):

    pass 1 of 4
    101print("Graph edges:")102for nodeA, neighbors['B', 'C'] in sorted(graphdefaultdict(<class 'list'>, {'A': ['B', 'C'], 'B': ['D'], 'C': ['D'], 'D': ['E']}).items()):103    print(f"  {nodeA} -> {neighbors['B', 'C']}")
    output  A -> ['B', 'C']
    All 4 passes — pass 1 is the card above
    passnodeneighbors
    1A['B', 'C']
    2B['D']
    3C['D']
    4D['E']
  15. text ← the quick brown fox jumps over the lazy dog, word_positions ← defaultdict(<class 'list'>, {})

    105# Word index106print("\nWord index:")107108text→ the quick brown fox jumps over the lazy dog = "the quick brown fox jumps over the lazy dog"109word_positions→ defaultdict(<class 'list'>, {}) = defaultdict(list)
    output
    Word index:
  16. word_positions[word] ← [0]

    pass 1 of 9
    111for i0, wordthe in enumerate(textthe quick brown fox jumps over the lazy dog.split()):112    word_positions[word]→ [0].append(i0)
    All 9 passes — pass 1 is the card above
    passiwordword_positions[word]
    10the[] [0]
    21quick[] [1]
    32brown[] [2]
    43fox[] [3]
    54jumps[] [4]
    65over[] [5]
    76the[0] [0, 6]
    87lazy[] [7]
    98dog[] [8]
  17. print(f"Text: '{text}'")

    114print(f"Text: '{textthe quick brown fox jumps over the lazy dog}'")115print("Word positions:")116for word in sorted(word_positions.keys()):
    outputText: 'the quick brown fox jumps over the lazy dog'
    Word positions:
  18. for word in sorted(word_positions.keys()):

    pass 1 of 8
    115print("Word positions:")116for wordbrown in sorted(word_positionsdefaultdict(<class 'list'>, {'the': [0, 6], 'quick': [1], 'brown': [2], 'fox': [3], 'jumps': [4], 'over': [5], 'lazy': [7], 'dog': [8]}).keys()):117    print(f"  '{wordbrown}': {word_positions[word][2]}")
    output  'brown': [2]
    All 8 passes — pass 1 is the card above
    passwordword_positions[word]
    1brown[2]
    2dog[8]
    3fox[3]
    4jumps[4]
    5lazy[7]
    6over[5]
    7quick[1]
    8the[0, 6]
  19. info ← defaultdict(⟨function default_value B⟩, {}), info[’name’] ← Alice

    119# Custom default factory120print("\nCustom default factory:")121122def default_value():123    return "N/A"124125info→ defaultdict(⟨function default_value B⟩, {}) = defaultdict(default_value⟨function default_value B⟩)126info['name']→ Alice = 'Alice'127info['age']→ 30 = 30128129print(f"Name: {info['name']Alice}")130print(f"Age: {info['age']30}")131print(f"City: {info['city']N/A}")  # Returns "N/A"132133# Matrix representation134print("\nMatrix representation:")135136matrix→ defaultdict(<function <lambda> at ⟨addr C⟩>, {}) = defaultdict(lambda: defaultdict(int))137138matrix[0][0]→ 1 = 1139matrix[0][2]→ 3 = 3140matrix[1][1]→ 5 = 5141matrix[2][0]→ 7 = 7142143print("Sparse matrix:")144for i in range(3):
    output
    Custom default factory:
    Name: Alice
    Age: 30
    City: N/A
    
    Matrix representation:
    Sparse matrix:
  20. row ← [1, 0, 3]

    pass 1 of 3
    143print("Sparse matrix:")144for i0 in range(3):145    row→ [1, 0, 3] = [matrix[i][j](empty) for j in range(3)]146    print(f"  {row[1, 0, 3]}")
    output  [1, 0, 3]
    All 3 passes — pass 1 is the card above
    passirow
    10[1, 0, 3]
    21[0, 5, 0]
    32[7, 0, 0]
  21. dd ← defaultdict(<class 'list'>, {}), dd[’a’] ← [1], dd[’b’] ← [2]

    148# Convert to regular dict149print("\nConvert to regular dict:")150151dd→ defaultdict(<class 'list'>, {}) = defaultdict(list)152dd['a']→ [1].append(1)153dd['b']→ [2].append(2)154155print(f"DefaultDict: {dddefaultdict(<class 'list'>, {'a': [1], 'b': [2]})}")156print(f"Regular dict: {dict(dddefaultdict(<class 'list'>, {'a': [1], 'b': [2]}))}")157158# Access after conversion159regular→ {'a': [1], 'b': [2]} = dict(dddefaultdict(<class 'list'>, {'a': [1], 'b': [2]}))160try:
    output
    Convert to regular dict:
    DefaultDict: defaultdict(<class 'list'>, {'a': [1], 'b': [2]})
    Regular dict: {'a': [1], 'b': [2]}
  22. try:

    159regular = dict(dd)160try:161    regular['c'](empty).append(3)162except KeyError:
  23. except KeyError:

    161    regular['c'].append(3)162except KeyError:163    print("KeyError on regular dict (expected)")
    outputKeyError on regular dict (expected)
  24. data ← [1, 2, 2, 3, 3, 3, 4, 4, 4, 4], freq ← defaultdict(<class 'int'>, {})

    165# Frequency table166print("\nFrequency table:")167168data→ [1, 2, 2, 3, 3, 3, 4, 4, 4, 4] = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]169freq→ defaultdict(<class 'int'>, {}) = defaultdict(int)
    output
    Frequency table:
  25. freq[n] ← 1

    pass 1 of 10
    171for n1 in data[1, 2, 2, 3, 3, 3, 4, 4, 4, 4]:172    freq[n]→ 1 += 1
    All 10 passes — pass 1 is the card above
    passnfreq[n]
    110 1
    220 1
    321 2
    430 1
    531 2
    632 3
    740 1
    841 2
    942 3
    1043 4
  26. print(f"Data: {data}")

    174print(f"Data: {data[1, 2, 2, 3, 3, 3, 4, 4, 4, 4]}")175print("Frequency:")176for num in sorted(freq.keys()):
    outputData: [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
    Frequency:
  27. bar ← █

    pass 1 of 4
    175print("Frequency:")176for num1 in sorted(freqdefaultdict(<class 'int'>, {1: 1, 2: 2, 3: 3, 4: 4}).keys()):177    bar→ █ = '█' * freq[num]1178    print(f"  {num1}: {bar} ({freq[num]1})")
    output  1: █ (1)
    All 4 passes — pass 1 is the card above
    passnumfreq[num]bar
    111
    222██
    333███
    444████
defaultdict A dict that calls a factory function for missing keys - eliminates KeyError checks and simplifies grouping patterns.

deque

Double-ended queue for efficient operations:

deque.py
Replay: real traced execution (multi-file project)
# deque examples

from collections import deque

# Basic deque
print("Basic deque:")

dq = deque([1, 2, 3, 4, 5])
print(f"Deque: {dq}")

# Append to right
dq.append(6)
print(f"After append(6): {dq}")

# Append to left
dq.appendleft(0)
print(f"After appendleft(0): {dq}")

# Pop from right
right = dq.pop()
print(f"Popped from right: {right}")
print(f"After pop(): {dq}")

# Pop from left
left = dq.popleft()
print(f"Popped from left: {left}")
print(f"After popleft(): {dq}")

# Extend deque
print("\nExtend deque:")

dq = deque([1, 2, 3])
print(f"Original: {dq}")

dq.extend([4, 5, 6])
print(f"After extend([4,5,6]): {dq}")

dq.extendleft([0, -1, -2])
print(f"After extendleft([0,-1,-2]): {dq}")

# Rotate deque
print("\nRotate deque:")

dq = deque([1, 2, 3, 4, 5])
print(f"Original: {dq}")

dq.rotate(2)
print(f"Rotate 2: {dq}")

dq.rotate(-3)
print(f"Rotate -3: {dq}")

# Maxlen deque
print("\nMaxlen deque:")

# Fixed-size deque
dq = deque(maxlen=3)

for i in range(1, 8):
    dq.append(i)
    print(f"Append {i}: {dq}")

# Recent items buffer
print("\nRecent items buffer:")

recent = deque(maxlen=5)

actions = ['open', 'save', 'edit', 'copy', 'paste', 'delete', 'undo', 'redo']

for action in actions:
    recent.append(action)
    print(f"Action '{action}': {list(recent)}")

# Queue operations
print("\nQueue operations:")

queue = deque()

# Enqueue
for item in ['A', 'B', 'C', 'D']:
    queue.append(item)
    print(f"Enqueue {item}: {queue}")

# Dequeue
while queue:
    item = queue.popleft()
    print(f"Dequeue {item}: {queue}")

# Stack operations
print("\nStack operations:")

stack = deque()

# Push
for item in [1, 2, 3, 4]:
    stack.append(item)
    print(f"Push {item}: {stack}")

# Pop
while stack:
    item = stack.pop()
    print(f"Pop {item}: {stack}")

# Palindrome check
print("\nPalindrome check:")

def is_palindrome(s):
    dq = deque(s.lower())
    while len(dq) > 1:
        if dq.popleft() != dq.pop():
            return False
    return True

words = ['racecar', 'hello', 'madam', 'python']
for word in words:
    print(f"'{word}': {is_palindrome(word)}")

# Circular buffer
print("\nCircular buffer:")

buffer = deque(maxlen=5)

for i in range(10):
    buffer.append(i)
    if i >= 4:
        print(f"Buffer: {list(buffer)} (avg: {sum(buffer)/len(buffer):.1f})")

# Sliding window
print("\nSliding window:")

data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
window_size = 3

window = deque(maxlen=window_size)

for num in data:
    window.append(num)
    if len(window) == window_size:
        avg = sum(window) / len(window)
        print(f"Window {list(window)}: avg = {avg:.1f}")

# BFS queue
print("\nBFS queue:")

graph = {
    'A': ['B', 'C'],
    'B': ['D', 'E'],
    'C': ['F'],
    'D': [],
    'E': ['F'],
    'F': []
}

def bfs(graph, start):
    visited = set()
    queue = deque([start])
    order = []

    while queue:
        node = queue.popleft()
        if node not in visited:
            visited.add(node)
            order.append(node)
            queue.extend(n for n in graph[node] if n not in visited)

    return order

print(f"BFS from 'A': {bfs(graph, 'A')}")

# Reverse with deque
print("\nReverse with deque:")

items = [1, 2, 3, 4, 5]
dq = deque(items)

dq.reverse()
print(f"Original: {items}")
print(f"Reversed: {list(dq)}")

# Index and count
print("\nIndex and count:")

dq = deque([1, 2, 3, 2, 4, 2, 5])
print(f"Deque: {dq}")
print(f"Count of 2: {dq.count(2)}")
print(f"Index of 2: {dq.index(2)}")
print(f"Index of 2 (start at 2): {dq.index(2, 2)}")

  1. dq ← deque([1, 2, 3, 4, 5]), right ← 6, left ← 0

    5# Basic deque6print("Basic deque:")78dq→ deque([1, 2, 3, 4, 5]) = deque([1, 2, 3, 4, 5])9print(f"Deque: {dqdeque([1, 2, 3, 4, 5])}")1011# Append to right12dq→ deque([1, 2, 3, 4, 5, 6]).append(6)13print(f"After append(6): {dqdeque([1, 2, 3, 4, 5, 6])}")1415# Append to left16dq→ deque([0, 1, 2, 3, 4, 5, 6]).appendleft(0)17print(f"After appendleft(0): {dqdeque([0, 1, 2, 3, 4, 5, 6])}")1819# Pop from right20right→ 6 = dq→ deque([0, 1, 2, 3, 4, 5]).pop()21print(f"Popped from right: {right6}")22print(f"After pop(): {dqdeque([0, 1, 2, 3, 4, 5])}")2324# Pop from left25left→ 0 = dq→ deque([1, 2, 3, 4, 5]).popleft()26print(f"Popped from left: {left0}")27print(f"After popleft(): {dqdeque([1, 2, 3, 4, 5])}")2829# Extend deque30print("\nExtend deque:")3132dq→ deque([1, 2, 3]) = deque([1, 2, 3])33print(f"Original: {dqdeque([1, 2, 3])}")3435dq→ deque([1, 2, 3, 4, 5, 6]).extend([4, 5, 6])36print(f"After extend([4,5,6]): {dqdeque([1, 2, 3, 4, 5, 6])}")3738dq→ deque([-2, -1, 0, 1, 2, 3, 4, 5, 6]).extendleft([0, -1, -2])39print(f"After extendleft([0,-1,-2]): {dqdeque([-2, -1, 0, 1, 2, 3, 4, 5, 6])}")4041# Rotate deque42print("\nRotate deque:")4344dq→ deque([1, 2, 3, 4, 5]) = deque([1, 2, 3, 4, 5])45print(f"Original: {dqdeque([1, 2, 3, 4, 5])}")4647dq→ deque([4, 5, 1, 2, 3]).rotate(2)48print(f"Rotate 2: {dqdeque([4, 5, 1, 2, 3])}")4950dq→ deque([2, 3, 4, 5, 1]).rotate(-3)51print(f"Rotate -3: {dqdeque([2, 3, 4, 5, 1])}")5253# Maxlen deque54print("\nMaxlen deque:")5556# Fixed-size deque57dq→ deque([], maxlen=3) = deque(maxlen=3)
    outputBasic deque:
    Deque: deque([1, 2, 3, 4, 5])
    After append(6): deque([1, 2, 3, 4, 5, 6])
    After appendleft(0): deque([0, 1, 2, 3, 4, 5, 6])
    Popped from right: 6
    After pop(): deque([0, 1, 2, 3, 4, 5])
    Popped from left: 0
    After popleft(): deque([1, 2, 3, 4, 5])
    
    Extend deque:
    Original: deque([1, 2, 3])
    After extend([4,5,6]): deque([1, 2, 3, 4, 5, 6])
    After extendleft([0,-1,-2]): deque([-2, -1, 0, 1, 2, 3, 4, 5, 6])
    
    Rotate deque:
    Original: deque([1, 2, 3, 4, 5])
    Rotate 2: deque([4, 5, 1, 2, 3])
    Rotate -3: deque([2, 3, 4, 5, 1])
    
    Maxlen deque:
  2. dq ← deque([1], maxlen=3)

    pass 1 of 7
    59for i1 in range(1, 8):60    dq→ deque([1], maxlen=3).append(i1)61    print(f"Append {i1}: {dqdeque([1], maxlen=3)}")
    outputAppend 1: deque([1], maxlen=3)
    All 7 passes — pass 1 is the card above
    passidq
    11deque([], maxlen=3) deque([1], maxlen=3)
    22deque([1], maxlen=3) deque([1, 2], maxlen=3)
    33deque([1, 2], maxlen=3) deque([1, 2, 3], maxlen=3)
    44deque([1, 2, 3], maxlen=3) deque([2, 3, 4], maxlen=3)
    55deque([2, 3, 4], maxlen=3) deque([3, 4, 5], maxlen=3)
    66deque([3, 4, 5], maxlen=3) deque([4, 5, 6], maxlen=3)
    77deque([4, 5, 6], maxlen=3) deque([5, 6, 7], maxlen=3)
  3. recent ← deque([], maxlen=5), actions ← ['open', 'save', 'edit', 'copy', 'paste', 'delete', 'undo', 'redo']

    63# Recent items buffer64print("\nRecent items buffer:")6566recent→ deque([], maxlen=5) = deque(maxlen=5)6768actions→ ['open', 'save', 'edit', 'copy', 'paste', 'delete', 'undo', 'redo'] = ['open', 'save', 'edit', 'copy', 'paste', 'delete', 'undo', 'redo']
    output
    Recent items buffer:
  4. recent ← deque(['open'], maxlen=5)

    pass 1 of 8
    70for actionopen in actions['open', 'save', 'edit', 'copy', 'paste', 'delete', 'undo', 'redo']:71    recent→ deque(['open'], maxlen=5).append(actionopen)72    print(f"Action '{actionopen}': {list(recentdeque(['open'], maxlen=5))}")
    outputAction 'open': ['open']
    All 8 passes — pass 1 is the card above
    passactionrecent
    1opendeque([], maxlen=5) deque(['open'], maxlen=5)
    2savedeque(['open'], maxlen=5) deque(['open', 'save'], maxlen=5)
    3editdeque(['open', 'save'], maxlen=5) deque(['open', 'save', 'edit'], maxlen=5)
    4copydeque(['open', 'save', 'edit'], maxlen=5) deque(['open', 'save', 'edit', 'copy'], maxlen=5)
    5pastedeque(['open', 'save', 'edit', 'copy'], maxlen=5) deque(['open', 'save', 'edit', 'copy', 'paste'], maxlen=5)
    6deletedeque(['open', 'save', 'edit', 'copy', 'paste'], maxlen=5) deque(['save', 'edit', 'copy', 'paste', 'delete'], maxlen=5)
    7undodeque(['save', 'edit', 'copy', 'paste', 'delete'], maxlen=5) deque(['edit', 'copy', 'paste', 'delete', 'undo'], maxlen=5)
    8redodeque(['edit', 'copy', 'paste', 'delete', 'undo'], maxlen=5) deque(['copy', 'paste', 'delete', 'undo', 'redo'], maxlen=5)
  5. queue ← deque([])

    74# Queue operations75print("\nQueue operations:")7677queue→ deque([]) = deque()
    output
    Queue operations:
  6. queue ← deque(['A'])

    pass 1 of 4
    79# Enqueue80for itemA in ['A', 'B', 'C', 'D']:81    queue→ deque(['A']).append(itemA)82    print(f"Enqueue {itemA}: {queuedeque(['A'])}")
    outputEnqueue A: deque(['A'])
    All 4 passes — pass 1 is the card above
    passitemqueue
    1Adeque([]) deque(['A'])
    2Bdeque(['A']) deque(['A', 'B'])
    3Cdeque(['A', 'B']) deque(['A', 'B', 'C'])
    4Ddeque(['A', 'B', 'C']) deque(['A', 'B', 'C', 'D'])
  7. queue ← deque(['B', 'C', 'D']), item ← A

    pass 1 of 4
    84# Dequeue85while queuedeque(['A', 'B', 'C', 'D']):86    item→ A = queue→ deque(['B', 'C', 'D']).popleft()87    print(f"Dequeue {itemA}: {queuedeque(['B', 'C', 'D'])}")
    outputDequeue A: deque(['B', 'C', 'D'])
    All 4 passes — pass 1 is the card above
    passqueueitem
    1deque(['A', 'B', 'C', 'D']) deque(['B', 'C', 'D'])A
    2deque(['B', 'C', 'D']) deque(['C', 'D'])B
    3deque(['C', 'D']) deque(['D'])C
    4deque(['D']) deque([])D
  8. stack ← deque([])

    89# Stack operations90print("\nStack operations:")9192stack→ deque([]) = deque()
    output
    Stack operations:
  9. stack ← deque([1])

    pass 1 of 4
    94# Push95for item1 in [1, 2, 3, 4]:96    stack→ deque([1]).append(item1)97    print(f"Push {item1}: {stackdeque([1])}")
    outputPush 1: deque([1])
    All 4 passes — pass 1 is the card above
    passitemstack
    11deque([]) deque([1])
    22deque([1]) deque([1, 2])
    33deque([1, 2]) deque([1, 2, 3])
    44deque([1, 2, 3]) deque([1, 2, 3, 4])
  10. stack ← deque([1, 2, 3]), item ← 4

    pass 1 of 4
    99# Pop100while stackdeque([1, 2, 3, 4]):101    item→ 4 = stack→ deque([1, 2, 3]).pop()102    print(f"Pop {item4}: {stackdeque([1, 2, 3])}")
    outputPop 4: deque([1, 2, 3])
    All 4 passes — pass 1 is the card above
    passstackitem
    1deque([1, 2, 3, 4]) deque([1, 2, 3])4
    2deque([1, 2, 3]) deque([1, 2])3
    3deque([1, 2]) deque([1])2
    4deque([1]) deque([])1
  11. words ← ['racecar', 'hello', 'madam', 'python']

    104# Palindrome check105print("\nPalindrome check:")106107def is_palindrome(s):108    dq = deque(s.lower())109    while len(dq) > 1:110        if dq.popleft() != dq.pop():111            return False112    return True113114words→ ['racecar', 'hello', 'madam', 'python'] = ['racecar', 'hello', 'madam', 'python']115for word in words:
    output
    Palindrome check:
  12. for word in words:

    pass 1 of 4
    114words = ['racecar', 'hello', 'madam', 'python']115for wordracecar in words['racecar', 'hello', 'madam', 'python']:116    print(f"'{wordracecar}': {is_palindrome(word)}")
    All 4 passes — pass 1 is the card above
    passworddq
    1racecar
    2hellodeque(['e', 'l', 'l'])
    3madam
    4pythondeque(['y', 't', 'h', 'o'])
  13. dq ← deque(['r', 'a', 'c', 'e', 'c', 'a', 'r'])

    pass 1 of 4
    107def is_palindrome(sracecar):108    dq→ deque(['r', 'a', 'c', 'e', 'c', 'a', 'r']) = deque(sracecar.lower())109    while len(dq) > 1:
    All 4 passes — pass 1 is the card above
    passsdq
    1racecardeque(['r', 'a', 'c', 'e', 'c', 'a', 'r'])
    2hellodeque(['h', 'e', 'l', 'l', 'o'])
    3madamdeque(['m', 'a', 'd', 'a', 'm'])
    4pythondeque(['p', 'y', 't', 'h', 'o', 'n'])
  14. while len(dq) > 1:

    pass 1 of 7
    108dq = deque(s.lower())109while len(dqdeque(['r', 'a', 'c', 'e', 'c', 'a', 'r'])) > 1:110    if dq.popleft() != dq.pop():111        return False
    All 7 passes — pass 1 is the card above
    passdq
    1deque(['r', 'a', 'c', 'e', 'c', 'a', 'r'])
    2deque(['a', 'c', 'e', 'c', 'a'])
    3deque(['c', 'e', 'c'])
    4deque(['h', 'e', 'l', 'l', 'o'])
    5deque(['m', 'a', 'd', 'a', 'm'])
    6deque(['a', 'd', 'a'])
    7deque(['p', 'y', 't', 'h', 'o', 'n'])
  15. return True

    111        return False112return True
  16. print(f"'{word}': {is_palindrome(word)}")

    115for word in words:116    print(f"'{wordracecar}': {is_palindrome(word)}")
    output'racecar': True
  17. if dq.popleft() != dq.pop():

    pass 1 of 2
    109while len(dq) > 1:110    if dqdeque(['e', 'l', 'l']).popleft() != dq.pop():111        return False112return True
  18. print(f"'{word}': {is_palindrome(word)}")

    115for word in words:116    print(f"'{wordhello}': {is_palindrome(word)}")
    output'hello': False
  19. return True

    111        return False112return True
  20. print(f"'{word}': {is_palindrome(word)}")

    115for word in words:116    print(f"'{wordmadam}': {is_palindrome(word)}")
    output'madam': True
  21. if dq.popleft() != dq.pop():

    pass 2 of 2
    109while len(dq) > 1:110    if dqdeque(['y', 't', 'h', 'o']).popleft() != dq.pop():111        return False112return True
  22. print(f"'{word}': {is_palindrome(word)}")

    115for word in words:116    print(f"'{wordpython}': {is_palindrome(word)}")
    output'python': False
  23. buffer ← deque([], maxlen=5)

    118# Circular buffer119print("\nCircular buffer:")120121buffer→ deque([], maxlen=5) = deque(maxlen=5)
    output
    Circular buffer:
  24. buffer ← deque([0], maxlen=5)

    pass 1 of 10
    123for i0 in range(10):124    buffer→ deque([0], maxlen=5).append(i0)125    if i >= 4:
    All 10 passes — pass 1 is the card above
    passibuffer
    10deque([], maxlen=5) deque([0], maxlen=5)
    21deque([0], maxlen=5) deque([0, 1], maxlen=5)
    32deque([0, 1], maxlen=5) deque([0, 1, 2], maxlen=5)
    43deque([0, 1, 2], maxlen=5) deque([0, 1, 2, 3], maxlen=5)
    54deque([0, 1, 2, 3], maxlen=5) deque([0, 1, 2, 3, 4], maxlen=5)
    65deque([0, 1, 2, 3, 4], maxlen=5) deque([1, 2, 3, 4, 5], maxlen=5)
    76deque([1, 2, 3, 4, 5], maxlen=5) deque([2, 3, 4, 5, 6], maxlen=5)
    87deque([2, 3, 4, 5, 6], maxlen=5) deque([3, 4, 5, 6, 7], maxlen=5)
    98deque([3, 4, 5, 6, 7], maxlen=5) deque([4, 5, 6, 7, 8], maxlen=5)
    109deque([4, 5, 6, 7, 8], maxlen=5) deque([5, 6, 7, 8, 9], maxlen=5)
  25. if i >= 4:

    pass 1 of 6
    124buffer.append(i)125if i4 >= 4:126    print(f"Buffer: {list(bufferdeque([0, 1, 2, 3, 4], maxlen=5))} (avg: {sum(buffer)/len(buffer):.1f})")
    outputBuffer: [0, 1, 2, 3, 4] (avg: 2.0)
    All 6 passes — pass 1 is the card above
    passibuffer
    14deque([0, 1, 2, 3, 4], maxlen=5)
    25deque([1, 2, 3, 4, 5], maxlen=5)
    36deque([2, 3, 4, 5, 6], maxlen=5)
    47deque([3, 4, 5, 6, 7], maxlen=5)
    58deque([4, 5, 6, 7, 8], maxlen=5)
    69deque([5, 6, 7, 8, 9], maxlen=5)
  26. data ← [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], window_size ← 3, window ← deque([], maxlen=3)

    128# Sliding window129print("\nSliding window:")130131data→ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]132window_size→ 3 = 3133134window→ deque([], maxlen=3) = deque(maxlen=window_size3)
    output
    Sliding window:
  27. window ← deque([1], maxlen=3)

    pass 1 of 10
    136for num1 in data[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]:137    window→ deque([1], maxlen=3).append(num1)138    if len(window) == window_size:
    All 10 passes — pass 1 is the card above
    passnumwindow
    11deque([], maxlen=3) deque([1], maxlen=3)
    22deque([1], maxlen=3) deque([1, 2], maxlen=3)
    33deque([1, 2], maxlen=3) deque([1, 2, 3], maxlen=3)
    44deque([1, 2, 3], maxlen=3) deque([2, 3, 4], maxlen=3)
    55deque([2, 3, 4], maxlen=3) deque([3, 4, 5], maxlen=3)
    66deque([3, 4, 5], maxlen=3) deque([4, 5, 6], maxlen=3)
    77deque([4, 5, 6], maxlen=3) deque([5, 6, 7], maxlen=3)
    88deque([5, 6, 7], maxlen=3) deque([6, 7, 8], maxlen=3)
    99deque([6, 7, 8], maxlen=3) deque([7, 8, 9], maxlen=3)
    1010deque([7, 8, 9], maxlen=3) deque([8, 9, 10], maxlen=3)
  28. avg ← 2.0

    pass 1 of 8
    137window.append(num)138if len(windowdeque([1, 2, 3], maxlen=3)) == window_size3:139    avg→ 2.0 = sum(windowdeque([1, 2, 3], maxlen=3)) / len(window)140    print(f"Window {list(windowdeque([1, 2, 3], maxlen=3))}: avg = {avg2.0:.1f}")
    outputWindow [1, 2, 3]: avg = 2.0
    All 8 passes — pass 1 is the card above
    passwindowavg
    1deque([1, 2, 3], maxlen=3)2.0
    2deque([2, 3, 4], maxlen=3)3.0
    3deque([3, 4, 5], maxlen=3)4.0
    4deque([4, 5, 6], maxlen=3)5.0
    5deque([5, 6, 7], maxlen=3)6.0
    6deque([6, 7, 8], maxlen=3)7.0
    7deque([7, 8, 9], maxlen=3)8.0
    8deque([8, 9, 10], maxlen=3)9.0
  29. graph ← {'A': ['B', 'C'], 'B': ['D', 'E'], 'C': ['F'], 'D': [], 'E': ['F'], 'F': []}

    142# BFS queue143print("\nBFS queue:")144145graph→ {'A': ['B', 'C'], 'B': ['D', 'E'], 'C': ['F'], 'D': [], 'E': ['F'], 'F': []} = {146    'A': ['B', 'C'],147    'B': ['D', 'E'],148    'C': ['F'],149    'D': [],150    'E': ['F'],151    'F': []152}153154def bfs(graph, start):155    visited = set()156    queue = deque([start])157    order = []158    159    while queue:160        node = queue.popleft()161        if node not in visited:162            visited.add(node)163            order.append(node)164            queue.extend(n for n in graph[node] if n not in visited)165    166    return order167168print(f"BFS from 'A': {bfs(graph{'A': ['B', 'C'], 'B': ['D', 'E'], 'C': ['F'], 'D': [], 'E': ['F'], 'F': []}, 'A')}")
    output
    BFS queue:
  30. visited ← set(), queue ← deque(['A']), order ← []

    154def bfs(graph{'A': ['B', 'C'], 'B': ['D', 'E'], 'C': ['F'], 'D': [], 'E': ['F'], 'F': []}, startA):155    visited→ set() = set()156    queue→ deque(['A']) = deque([startA])157    order→ [] = []
  31. queue ← deque([]), node ← A

    pass 1 of 7
    159while queuedeque(['A']):160    node→ A = queue→ deque([]).popleft()161    if node not in visited:
    All 7 passes — pass 1 is the card above
    passqueuenode
    1deque(['A']) deque([])A
    2deque(['B', 'C']) deque(['C'])B
    3deque(['C', 'D', 'E']) deque(['D', 'E'])C
    4deque(['D', 'E', 'F']) deque(['E', 'F'])D
    5deque(['E', 'F']) deque(['F'])E
    6deque(['F', 'F']) deque(['F'])F
    7deque(['F']) deque([])F
  32. visited ← {'A'}, order ← ['A'], queue ← deque(['B', 'C'])

    pass 1 of 6
    160node = queue.popleft()161if nodeA not in visitedset():162    visited→ {'A'}.add(nodeA)163    order→ ['A'].append(nodeA)164    queue→ deque(['B', 'C']).extend(n for n in graph[node]['B', 'C'] if n not in visited{'A'})
    All 6 passes — pass 1 is the card above
    passnodegraph[node]visitedorderqueue
    1A['B', 'C']set() {'A'}[] ['A']deque([]) deque(['B', 'C'])
    2B['D', 'E']{'A'} {'A', 'B'}['A'] ['A', 'B']deque(['C']) deque(['C', 'D', 'E'])
    3C['F']{'A', 'B'} {'C', 'A', 'B'}['A', 'B'] ['A', 'B', 'C']deque(['D', 'E']) deque(['D', 'E', 'F'])
    4D[]{'C', 'A', 'B'} {'C', 'D', 'A', 'B'}['A', 'B', 'C'] ['A', 'B', 'C', 'D']deque(['E', 'F'])
    5E['F']{'C', 'D', 'A', 'B'} {'B', 'C', 'A', 'D', 'E'}['A', 'B', 'C', 'D'] ['A', 'B', 'C', 'D', 'E']deque(['F']) deque(['F', 'F'])
    6F[]{'B', 'C', 'A', 'D', 'E'} {'B', 'C', 'A', 'D', 'F', 'E'}['A', 'B', 'C', 'D', 'E'] ['A', 'B', 'C', 'D', 'E', 'F']deque(['F'])
  33. return order

    166return order['A', 'B', 'C', 'D', 'E', 'F']
  34. items ← [1, 2, 3, 4, 5], dq ← deque([1, 2, 3, 4, 5])

    168print(f"BFS from 'A': {bfs(graph{'A': ['B', 'C'], 'B': ['D', 'E'], 'C': ['F'], 'D': [], 'E': ['F'], 'F': []}, 'A')}")169170# Reverse with deque171print("\nReverse with deque:")172173items→ [1, 2, 3, 4, 5] = [1, 2, 3, 4, 5]174dq→ deque([1, 2, 3, 4, 5]) = deque(items[1, 2, 3, 4, 5])175176dq→ deque([5, 4, 3, 2, 1]).reverse()177print(f"Original: {items[1, 2, 3, 4, 5]}")178print(f"Reversed: {list(dqdeque([5, 4, 3, 2, 1]))}")179180# Index and count181print("\nIndex and count:")182183dq→ deque([1, 2, 3, 2, 4, 2, 5]) = deque([1, 2, 3, 2, 4, 2, 5])184print(f"Deque: {dqdeque([1, 2, 3, 2, 4, 2, 5])}")185print(f"Count of 2: {dqdeque([1, 2, 3, 2, 4, 2, 5]).count(2)}")186print(f"Index of 2: {dqdeque([1, 2, 3, 2, 4, 2, 5]).index(2)}")187print(f"Index of 2 (start at 2): {dqdeque([1, 2, 3, 2, 4, 2, 5]).index(2, 2)}")
    outputBFS from 'A': ['A', 'B', 'C', 'D', 'E', 'F']
    
    Reverse with deque:
    Original: [1, 2, 3, 4, 5]
    Reversed: [5, 4, 3, 2, 1]
    
    Index and count:
    Deque: deque([1, 2, 3, 2, 4, 2, 5])
    Count of 2: 3
    Index of 2: 1
    Index of 2 (start at 2): 3
deque A list-like container with O(1) appends and pops from both ends - ideal for queues, sliding windows, and recent-item caches.

OrderedDict

Dictionary that remembers insertion order:

ordereddict.py
Replay: real traced execution (multi-file project)
# OrderedDict examples

from collections import OrderedDict

# Basic OrderedDict
print("Basic OrderedDict:")

# Note: Regular dict preserves order in Python 3.7+
# OrderedDict has additional methods

od = OrderedDict()
od['first'] = 1
od['second'] = 2
od['third'] = 3

print(f"OrderedDict: {od}")
print(f"Keys: {list(od.keys())}")

# Move to end
print("\nMove to end:")

od = OrderedDict([('a', 1), ('b', 2), ('c', 3)])
print(f"Original: {od}")

od.move_to_end('a')
print(f"Move 'a' to end: {od}")

od.move_to_end('c', last=False)
print(f"Move 'c' to front: {od}")

# Pop from front
print("\nPop from front:")

od = OrderedDict([('first', 1), ('second', 2), ('third', 3)])
print(f"Original: {od}")

item = od.popitem(last=False)
print(f"Popped from front: {item}")
print(f"Remaining: {od}")

# Pop from end
print("\nPop from end:")

od = OrderedDict([('a', 1), ('b', 2), ('c', 3)])
print(f"Original: {od}")

item = od.popitem(last=True)
print(f"Popped from end: {item}")
print(f"Remaining: {od}")

# LRU cache simulation
print("\nLRU cache simulation:")

class LRUCache:
    def __init__(self, capacity):
        self.cache = OrderedDict()
        self.capacity = capacity

    def get(self, key):
        if key in self.cache:
            self.cache.move_to_end(key)
            return self.cache[key]
        return None

    def put(self, key, value):
        if key in self.cache:
            self.cache.move_to_end(key)
        self.cache[key] = value
        if len(self.cache) > self.capacity:
            self.cache.popitem(last=False)

cache = LRUCache(3)
cache.put('a', 1)
cache.put('b', 2)
cache.put('c', 3)
print(f"Cache: {cache.cache}")

cache.get('a')  # Access 'a'
print(f"After get('a'): {cache.cache}")

cache.put('d', 4)  # Evicts 'b'
print(f"After put('d', 4): {cache.cache}")

# Sorted dict
print("\nSorted dict:")

data = {'banana': 3, 'apple': 5, 'cherry': 2, 'date': 4}
sorted_dict = OrderedDict(sorted(data.items()))

print(f"Original: {data}")
print(f"Sorted: {sorted_dict}")

# Sort by value
sorted_by_value = OrderedDict(sorted(data.items(), key=lambda x: x[1]))
print(f"Sorted by value: {sorted_by_value}")

# Insertion order comparison
print("\nInsertion order comparison:")

# Two dicts with same items, different order
od1 = OrderedDict([('a', 1), ('b', 2), ('c', 3)])
od2 = OrderedDict([('c', 3), ('b', 2), ('a', 1)])

print(f"OD1: {od1}")
print(f"OD2: {od2}")
print(f"Equal? {od1 == od2}")  # False (different order)

# Regular dicts ignore order
d1 = {'a': 1, 'b': 2, 'c': 3}
d2 = {'c': 3, 'b': 2, 'a': 1}
print(f"Regular dicts equal? {d1 == d2}")  # True

# Reverse iteration
print("\nReverse iteration:")

od = OrderedDict([('first', 1), ('second', 2), ('third', 3)])

print("Forward:")
for key, value in od.items():
    print(f"  {key}: {value}")

print("Reverse:")
for key, value in reversed(od.items()):
    print(f"  {key}: {value}")

# Maintain order in processing
print("\nMaintain order in processing:")

tasks = OrderedDict()
tasks['setup'] = 'Initialize system'
tasks['process'] = 'Process data'
tasks['validate'] = 'Validate results'
tasks['cleanup'] = 'Clean up resources'

print("Task sequence:")
for i, (name, description) in enumerate(tasks.items(), 1):
    print(f"  {i}. {name}: {description}")

# Recent items tracking
print("\nRecent items tracking:")

recent = OrderedDict()
max_recent = 5

actions = ['open', 'save', 'edit', 'copy', 'paste', 'open', 'delete', 'undo']

for action in actions:
    if action in recent:
        recent.move_to_end(action)
    else:
        recent[action] = True
        if len(recent) > max_recent:
            recent.popitem(last=False)

    print(f"After '{action}': {list(recent.keys())}")

# Dictionary with default order
print("\nDictionary with default order:")

# Python 3.7+ dicts are ordered, but OrderedDict has extra methods
config = OrderedDict([
    ('host', 'localhost'),
    ('port', 8080),
    ('debug', True),
    ('timeout', 30)
])

print("Config:")
for key, value in config.items():
    print(f"  {key} = {value}")

# Reorder
config.move_to_end('debug', last=False)
print("\nAfter moving debug to front:")
for key, value in config.items():
    print(f"  {key} = {value}")

  1. od ← OrderedDict(), od[’first’] ← 1, od[’second’] ← 2, od[’third’] ← 3

    5# Basic OrderedDict6print("Basic OrderedDict:")78# Note: Regular dict preserves order in Python 3.7+9# OrderedDict has additional methods1011od→ OrderedDict() = OrderedDict()12od['first']→ 1 = 113od['second']→ 2 = 214od['third']→ 3 = 31516print(f"OrderedDict: {odOrderedDict({'first': 1, 'second': 2, 'third': 3})}")17print(f"Keys: {list(odOrderedDict({'first': 1, 'second': 2, 'third': 3}).keys())}")1819# Move to end20print("\nMove to end:")2122od→ OrderedDict({'a': 1, 'b': 2, 'c': 3}) = OrderedDict([('a', 1), ('b', 2), ('c', 3)])23print(f"Original: {odOrderedDict({'a': 1, 'b': 2, 'c': 3})}")2425od→ OrderedDict({'b': 2, 'c': 3, 'a': 1}).move_to_end('a')26print(f"Move 'a' to end: {odOrderedDict({'b': 2, 'c': 3, 'a': 1})}")2728od→ OrderedDict({'c': 3, 'b': 2, 'a': 1}).move_to_end('c', last=False)29print(f"Move 'c' to front: {odOrderedDict({'c': 3, 'b': 2, 'a': 1})}")3031# Pop from front32print("\nPop from front:")3334od→ OrderedDict({'first': 1, 'second': 2, 'third': 3}) = OrderedDict([('first', 1), ('second', 2), ('third', 3)])35print(f"Original: {odOrderedDict({'first': 1, 'second': 2, 'third': 3})}")3637item→ ('first', 1) = od→ OrderedDict({'second': 2, 'third': 3}).popitem(last=False)38print(f"Popped from front: {item('first', 1)}")39print(f"Remaining: {odOrderedDict({'second': 2, 'third': 3})}")4041# Pop from end42print("\nPop from end:")4344od→ OrderedDict({'a': 1, 'b': 2, 'c': 3}) = OrderedDict([('a', 1), ('b', 2), ('c', 3)])45print(f"Original: {odOrderedDict({'a': 1, 'b': 2, 'c': 3})}")4647item→ ('c', 3) = od→ OrderedDict({'a': 1, 'b': 2}).popitem(last=True)48print(f"Popped from end: {item('c', 3)}")49print(f"Remaining: {odOrderedDict({'a': 1, 'b': 2})}")5051# LRU cache simulation52print("\nLRU cache simulation:")5354class LRUCache:55    def __init__(self, capacity):56        self.cache = OrderedDict()57        self.capacity = capacity58    59    def get(self, key):60        if key in self.cache:61            self.cache.move_to_end(key)62            return self.cache[key]63        return None64    65    def put(self, key, value):66        if key in self.cache:67            self.cache.move_to_end(key)68        self.cache[key] = value69        if len(self.cache) > self.capacity:70            self.cache.popitem(last=False)7172cache = LRUCache(3)73cache.put('a', 1)
    outputBasic OrderedDict:
    OrderedDict: OrderedDict({'first': 1, 'second': 2, 'third': 3})
    Keys: ['first', 'second', 'third']
    
    Move to end:
    Original: OrderedDict({'a': 1, 'b': 2, 'c': 3})
    Move 'a' to end: OrderedDict({'b': 2, 'c': 3, 'a': 1})
    Move 'c' to front: OrderedDict({'c': 3, 'b': 2, 'a': 1})
    
    Pop from front:
    Original: OrderedDict({'first': 1, 'second': 2, 'third': 3})
    Popped from front: ('first', 1)
    Remaining: OrderedDict({'second': 2, 'third': 3})
    
    Pop from end:
    Original: OrderedDict({'a': 1, 'b': 2, 'c': 3})
    Popped from end: ('c', 3)
    Remaining: OrderedDict({'a': 1, 'b': 2})
    
    LRU cache simulation:
  2. self.cache ← OrderedDict(), self.capacity ← 3

    54class LRUCache:55    def __init__(self⟨LRUCache A⟩, capacity3):56        self.cache→ OrderedDict() = OrderedDict()57        self.capacity→ 3 = capacity3
  3. cache ← ⟨LRUCache A⟩

    72cache→ ⟨LRUCache A⟩ = LRUCache(3)73cache⟨LRUCache A⟩.put('a', 1)74cache.put('b', 2)
  4. self.cache[key] ← 1

    pass 1 of 4
    65def put(self⟨LRUCache A⟩, keya, value1):66    if key in self.cache:67        self.cache.move_to_end(key)68    self.cache[key]→ 1 = value169    if len(self.cache) > self.capacity:
    All 4 passes — pass 1 is the card above
    passkeyvalueself.capacityself.cache[key]self.cache
    1a11
    2b22
    3c33
    4d434OrderedDict({'b': 2, 'c': 3, 'a': 1, 'd': 4}) OrderedDict({'c': 3, 'a': 1, 'd': 4})
  5. cache.put('a', 1)

    72cache = LRUCache(3)73cache⟨LRUCache A⟩.put('a', 1)74cache⟨LRUCache A⟩.put('b', 2)75cache.put('c', 3)
  6. cache.put('b', 2)

    73cache.put('a', 1)74cache⟨LRUCache A⟩.put('b', 2)75cache⟨LRUCache A⟩.put('c', 3)76print(f"Cache: {cache.cache}")
  7. cache.put('c', 3)

    74cache.put('b', 2)75cache⟨LRUCache A⟩.put('c', 3)76print(f"Cache: {cache.cacheOrderedDict({'a': 1, 'b': 2, 'c': 3})}")7778cache⟨LRUCache A⟩.get('a')  # Access 'a'79print(f"After get('a'): {cache.cache}")
    outputCache: OrderedDict({'a': 1, 'b': 2, 'c': 3})
  8. def get(self, key):

    59def get(self⟨LRUCache A⟩, keya):60    if key in self.cache:61        self.cache.move_to_end(key)
  9. self.cache ← OrderedDict({'b': 2, 'c': 3, 'a': 1})

    59def get(self, key):60    if keya in self.cacheOrderedDict({'a': 1, 'b': 2, 'c': 3}):61        self.cache→ OrderedDict({'b': 2, 'c': 3, 'a': 1}).move_to_end(keya)62        return self.cache[key]163    return None
  10. cache.get('a') # Access 'a'

    78cache⟨LRUCache A⟩.get('a')  # Access 'a'79print(f"After get('a'): {cache.cacheOrderedDict({'b': 2, 'c': 3, 'a': 1})}")8081cache⟨LRUCache A⟩.put('d', 4)  # Evicts 'b'82print(f"After put('d', 4): {cache.cache}")
    outputAfter get('a'): OrderedDict({'b': 2, 'c': 3, 'a': 1})
  11. self.cache ← OrderedDict({'c': 3, 'a': 1, 'd': 4})

    68self.cache[key] = value69if len(self.cacheOrderedDict({'b': 2, 'c': 3, 'a': 1, 'd': 4})) > self.capacity3:70    self.cache→ OrderedDict({'c': 3, 'a': 1, 'd': 4}).popitem(last=False)
  12. data ← {'banana': 3, 'apple': 5, 'cherry': 2, 'date': 4}, sorted_dict ← OrderedDict({'apple': 5, 'banana': 3, 'cherry': 2, 'date': 4})

    81cache⟨LRUCache A⟩.put('d', 4)  # Evicts 'b'82print(f"After put('d', 4): {cache.cacheOrderedDict({'c': 3, 'a': 1, 'd': 4})}")8384# Sorted dict85print("\nSorted dict:")8687data→ {'banana': 3, 'apple': 5, 'cherry': 2, 'date': 4} = {'banana': 3, 'apple': 5, 'cherry': 2, 'date': 4}88sorted_dict→ OrderedDict({'apple': 5, 'banana': 3, 'cherry': 2, 'date': 4}) = OrderedDict(sorted(data{'banana': 3, 'apple': 5, 'cherry': 2, 'date': 4}.items()))8990print(f"Original: {data{'banana': 3, 'apple': 5, 'cherry': 2, 'date': 4}}")91print(f"Sorted: {sorted_dictOrderedDict({'apple': 5, 'banana': 3, 'cherry': 2, 'date': 4})}")9293# Sort by value94sorted_by_value→ OrderedDict({'cherry': 2, 'banana': 3, 'date': 4, 'apple': 5}) = OrderedDict(sorted(data{'banana': 3, 'apple': 5, 'cherry': 2, 'date': 4}.items(), key=lambda x: x[1]))95print(f"Sorted by value: {sorted_by_valueOrderedDict({'cherry': 2, 'banana': 3, 'date': 4, 'apple': 5})}")9697# Insertion order comparison98print("\nInsertion order comparison:")99100# Two dicts with same items, different order101od1→ OrderedDict({'a': 1, 'b': 2, 'c': 3}) = OrderedDict([('a', 1), ('b', 2), ('c', 3)])102od2→ OrderedDict({'c': 3, 'b': 2, 'a': 1}) = OrderedDict([('c', 3), ('b', 2), ('a', 1)])103104print(f"OD1: {od1OrderedDict({'a': 1, 'b': 2, 'c': 3})}")105print(f"OD2: {od2OrderedDict({'c': 3, 'b': 2, 'a': 1})}")106print(f"Equal? {od1OrderedDict({'a': 1, 'b': 2, 'c': 3}) == od2OrderedDict({'c': 3, 'b': 2, 'a': 1})}")  # False (different order)107108# Regular dicts ignore order109d1→ {'a': 1, 'b': 2, 'c': 3} = {'a': 1, 'b': 2, 'c': 3}110d2→ {'c': 3, 'b': 2, 'a': 1} = {'c': 3, 'b': 2, 'a': 1}111print(f"Regular dicts equal? {d1{'a': 1, 'b': 2, 'c': 3} == d2{'c': 3, 'b': 2, 'a': 1}}")  # True112113# Reverse iteration114print("\nReverse iteration:")115116od→ OrderedDict({'first': 1, 'second': 2, 'third': 3}) = OrderedDict([('first', 1), ('second', 2), ('third', 3)])117118print("Forward:")119for key, value in od.items():
    outputAfter put('d', 4): OrderedDict({'c': 3, 'a': 1, 'd': 4})
    
    Sorted dict:
    Original: {'banana': 3, 'apple': 5, 'cherry': 2, 'date': 4}
    Sorted: OrderedDict({'apple': 5, 'banana': 3, 'cherry': 2, 'date': 4})
    Sorted by value: OrderedDict({'cherry': 2, 'banana': 3, 'date': 4, 'apple': 5})
    
    Insertion order comparison:
    OD1: OrderedDict({'a': 1, 'b': 2, 'c': 3})
    OD2: OrderedDict({'c': 3, 'b': 2, 'a': 1})
    Equal? False
    Regular dicts equal? True
    
    Reverse iteration:
    Forward:
  13. for key, value in od.items():

    pass 1 of 3
    118print("Forward:")119for keyfirst, value1 in odOrderedDict({'first': 1, 'second': 2, 'third': 3}).items():120    print(f"  {keyfirst}: {value1}")
    output  first: 1
    All 3 passes — pass 1 is the card above
    passkeyvalue
    1first1
    2second2
    3third3
  14. print("Reverse:")

    122print("Reverse:")123for key, value in reversed(od.items()):
    outputReverse:
  15. for key, value in reversed(od.items()):

    pass 1 of 3
    122print("Reverse:")123for keythird, value3 in reversed(odOrderedDict({'first': 1, 'second': 2, 'third': 3}).items()):124    print(f"  {keythird}: {value3}")
    output  third: 3
    All 3 passes — pass 1 is the card above
    passkeyvalue
    1third3
    2second2
    3first1
  16. tasks ← OrderedDict(), tasks[’setup’] ← Initialize system, tasks[’process’] ← Process data

    126# Maintain order in processing127print("\nMaintain order in processing:")128129tasks→ OrderedDict() = OrderedDict()130tasks['setup']→ Initialize system = 'Initialize system'131tasks['process']→ Process data = 'Process data'132tasks['validate']→ Validate results = 'Validate results'133tasks['cleanup']→ Clean up resources = 'Clean up resources'134135print("Task sequence:")136for i, (name, description) in enumerate(tasks.items(), 1):
    output
    Maintain order in processing:
    Task sequence:
  17. for i, (name, description) in enumerate(tasks.items(), 1):

    pass 1 of 4
    135print("Task sequence:")136for i1, (namesetup, descriptionInitialize system) in enumerate(tasksOrderedDict({'setup': 'Initialize system', 'process': 'Process data', 'validate': 'Validate results', 'cleanup': 'Clean up resources'}).items(), 1):137    print(f"  {i1}. {namesetup}: {descriptionInitialize system}")
    output  1. setup: Initialize system
    All 4 passes — pass 1 is the card above
    passinamedescription
    11setupInitialize system
    22processProcess data
    33validateValidate results
    44cleanupClean up resources
  18. recent ← OrderedDict(), max_recent ← 5, actions ← ['open', 'save', 'edit', 'copy', 'paste', 'open', 'delete', 'undo']

    139# Recent items tracking140print("\nRecent items tracking:")141142recent→ OrderedDict() = OrderedDict()143max_recent→ 5 = 5144145actions→ ['open', 'save', 'edit', 'copy', 'paste', 'open', 'delete', 'undo'] = ['open', 'save', 'edit', 'copy', 'paste', 'open', 'delete', 'undo']
    output
    Recent items tracking:
  19. for action in actions:

    pass 1 of 8
    147for actionopen in actions['open', 'save', 'edit', 'copy', 'paste', 'open', 'delete', 'undo']:148    if action in recent:149        recent.move_to_end(action)
    All 8 passes — pass 1 is the card above
    passactionmax_recentrecent
    1open
    2save
    3edit
    4copy
    5paste
    6openOrderedDict({'open': True, 'save': True, 'edit': True, 'copy': True, 'paste': True}) OrderedDict({'save': True, 'edit': True, 'copy': True, 'paste': True, 'open': True})
    7delete5OrderedDict({'save': True, 'edit': True, 'copy': True, 'paste': True, 'open': True, 'delete': True}) OrderedDict({'edit': True, 'copy': True, 'paste': True, 'open': True, 'delete': True})
    8undo5OrderedDict({'edit': True, 'copy': True, 'paste': True, 'open': True, 'delete': True, 'undo': True}) OrderedDict({'copy': True, 'paste': True, 'open': True, 'delete': True, 'undo': True})
  20. recent[action] ← True

    pass 1 of 7
    148if action in recent:149    recent.move_to_end(action)150else:151    recent[action]→ True = True152    if len(recent) > max_recent:
    All 7 passes — pass 1 is the card above
    passmax_recentrecent[action]recent
    1True
    2True
    3True
    4True
    5True
    65TrueOrderedDict({'save': True, 'edit': True, 'copy': True, 'paste': True, 'open': True, 'delete': True}) OrderedDict({'edit': True, 'copy': True, 'paste': True, 'open': True, 'delete': True})
    75TrueOrderedDict({'edit': True, 'copy': True, 'paste': True, 'open': True, 'delete': True, 'undo': True}) OrderedDict({'copy': True, 'paste': True, 'open': True, 'delete': True, 'undo': True})
  21. print(f"After '{action}': {list(recent.keys())}")

    155print(f"After '{actionopen}': {list(recentOrderedDict({'open': True}).keys())}")
    outputAfter 'open': ['open']
  22. print(f"After '{action}': {list(recent.keys())}")

    155print(f"After '{actionsave}': {list(recentOrderedDict({'open': True, 'save': True}).keys())}")
    outputAfter 'save': ['open', 'save']
  23. print(f"After '{action}': {list(recent.keys())}")

    155print(f"After '{actionedit}': {list(recentOrderedDict({'open': True, 'save': True, 'edit': True}).keys())}")
    outputAfter 'edit': ['open', 'save', 'edit']
  24. print(f"After '{action}': {list(recent.keys())}")

    155print(f"After '{actioncopy}': {list(recentOrderedDict({'open': True, 'save': True, 'edit': True, 'copy': True}).keys())}")
    outputAfter 'copy': ['open', 'save', 'edit', 'copy']
  25. print(f"After '{action}': {list(recent.keys())}")

    155print(f"After '{actionpaste}': {list(recentOrderedDict({'open': True, 'save': True, 'edit': True, 'copy': True, 'paste': True}).keys())}")
    outputAfter 'paste': ['open', 'save', 'edit', 'copy', 'paste']
  26. recent ← OrderedDict({'save': True, 'edit': True, 'copy': True, 'paste': True, 'open': True})

    147for action in actions:148    if actionopen in recentOrderedDict({'open': True, 'save': True, 'edit': True, 'copy': True, 'paste': True}):149        recent→ OrderedDict({'save': True, 'edit': True, 'copy': True, 'paste': True, 'open': True}).move_to_end(actionopen)150    else:
  27. print(f"After '{action}': {list(recent.keys())}")

    155print(f"After '{actionopen}': {list(recentOrderedDict({'save': True, 'edit': True, 'copy': True, 'paste': True, 'open': True}).keys())}")
    outputAfter 'open': ['save', 'edit', 'copy', 'paste', 'open']
  28. recent ← OrderedDict({'edit': True, 'copy': True, 'paste': True, 'open': True, 'delete': True})

    pass 1 of 2
    151recent[action] = True152if len(recentOrderedDict({'save': True, 'edit': True, 'copy': True, 'paste': True, 'open': True, 'delete': True})) > max_recent5:153    recent→ OrderedDict({'edit': True, 'copy': True, 'paste': True, 'open': True, 'delete': True}).popitem(last=False)
  29. print(f"After '{action}': {list(recent.keys())}")

    155print(f"After '{actiondelete}': {list(recentOrderedDict({'edit': True, 'copy': True, 'paste': True, 'open': True, 'delete': True}).keys())}")
    outputAfter 'delete': ['edit', 'copy', 'paste', 'open', 'delete']
  30. recent ← OrderedDict({'copy': True, 'paste': True, 'open': True, 'delete': True, 'undo': True})

    pass 2 of 2
    151recent[action] = True152if len(recentOrderedDict({'edit': True, 'copy': True, 'paste': True, 'open': True, 'delete': True, 'undo': True})) > max_recent5:153    recent→ OrderedDict({'copy': True, 'paste': True, 'open': True, 'delete': True, 'undo': True}).popitem(last=False)
  31. print(f"After '{action}': {list(recent.keys())}")

    155print(f"After '{actionundo}': {list(recentOrderedDict({'copy': True, 'paste': True, 'open': True, 'delete': True, 'undo': True}).keys())}")
    outputAfter 'undo': ['copy', 'paste', 'open', 'delete', 'undo']
  32. config ← OrderedDict({'host': 'localhost', 'port': 8080, 'debug': True, 'timeout': 30})

    157# Dictionary with default order158print("\nDictionary with default order:")159160# Python 3.7+ dicts are ordered, but OrderedDict has extra methods161config→ OrderedDict({'host': 'localhost', 'port': 8080, 'debug': True, 'timeout': 30}) = OrderedDict([162    ('host', 'localhost'),163    ('port', 8080),164    ('debug', True),165    ('timeout', 30)166])167168print("Config:")169for key, value in config.items():
    output
    Dictionary with default order:
    Config:
  33. for key, value in config.items():

    pass 1 of 4
    168print("Config:")169for keyhost, valuelocalhost in configOrderedDict({'host': 'localhost', 'port': 8080, 'debug': True, 'timeout': 30}).items():170    print(f"  {keyhost} = {valuelocalhost}")
    output  host = localhost
    All 4 passes — pass 1 is the card above
    passkeyvalue
    1hostlocalhost
    2port8080
    3debugTrue
    4timeout30
  34. config ← OrderedDict({'debug': True, 'host': 'localhost', 'port': 8080, 'timeout': 30})

    172# Reorder173config→ OrderedDict({'debug': True, 'host': 'localhost', 'port': 8080, 'timeout': 30}).move_to_end('debug', last=False)174print("\nAfter moving debug to front:")175for key, value in config.items():
    output
    After moving debug to front:
  35. for key, value in config.items():

    pass 1 of 4
    174print("\nAfter moving debug to front:")175for keydebug, valueTrue in configOrderedDict({'debug': True, 'host': 'localhost', 'port': 8080, 'timeout': 30}).items():176    print(f"  {keydebug} = {valueTrue}")
    output  debug = True
    All 4 passes — pass 1 is the card above
    passkeyvalue
    1debugTrue
    2hostlocalhost
    3port8080
    4timeout30

ChainMap

Combine multiple dictionaries:

chainmap.py
Replay: real traced execution (multi-file project)
# ChainMap examples

from collections import ChainMap

# Basic ChainMap
print("Basic ChainMap:")

dict1 = {'a': 1, 'b': 2}
dict2 = {'b': 3, 'c': 4}
dict3 = {'c': 5, 'd': 6}

cm = ChainMap(dict1, dict2, dict3)

print(f"Dict1: {dict1}")
print(f"Dict2: {dict2}")
print(f"Dict3: {dict3}")
print(f"ChainMap: {dict(cm)}")

# First occurrence wins
print(f"cm['a']: {cm['a']}")  # From dict1
print(f"cm['b']: {cm['b']}")  # From dict1
print(f"cm['c']: {cm['c']}")  # From dict2
print(f"cm['d']: {cm['d']}")  # From dict3

# Configuration hierarchy
print("\nConfiguration hierarchy:")

# Default config
defaults = {
    'host': 'localhost',
    'port': 8080,
    'debug': False,
    'timeout': 30
}

# User config
user_config = {
    'port': 9000,
    'debug': True
}

# Command line args
cli_args = {
    'host': '192.168.1.1'
}

# Priority: CLI > User > Defaults
config = ChainMap(cli_args, user_config, defaults)

print("Final config:")
for key in defaults.keys():
    print(f"  {key}: {config[key]}")

# Modifications
print("\nModifications:")

dict1 = {'a': 1}
dict2 = {'b': 2}

cm = ChainMap(dict1, dict2)
print(f"Original: {dict(cm)}")

# Update (modifies first dict)
cm['a'] = 10
cm['c'] = 3

print(f"After update: {dict(cm)}")
print(f"Dict1: {dict1}")  # Modified
print(f"Dict2: {dict2}")  # Unchanged

# New child
print("\nNew child:")

base = {'a': 1, 'b': 2}
cm = ChainMap(base)

print(f"Base: {dict(cm)}")

# Create new child context
cm = cm.new_child({'a': 10, 'c': 3})
print(f"With child: {dict(cm)}")

# Can go back
cm = cm.parents
print(f"Back to base: {dict(cm)}")

# Scope simulation
print("\nScope simulation:")

# Global scope
global_scope = {'x': 10, 'y': 20}

# Function scope
def function():
    local_scope = {'x': 5, 'z': 30}
    scope = ChainMap(local_scope, global_scope)

    print(f"  x (local): {scope['x']}")
    print(f"  y (global): {scope['y']}")
    print(f"  z (local): {scope['z']}")

    return scope

print("Inside function:")
function()

# Context managers
print("\nContext managers:")

settings = {'theme': 'light', 'font': 'Arial'}

print(f"Original: {settings}")

# Temporary override
temp = ChainMap({'theme': 'dark'}, settings)
print(f"Temporary: {dict(temp)}")

# Original unchanged
print(f"Original: {settings}")

# Environment variables
print("\nEnvironment variables:")

# System defaults
system = {'EDITOR': 'vi', 'SHELL': '/bin/sh'}

# User preferences
user = {'EDITOR': 'nano', 'PAGER': 'less'}

# Current session
session = {'EDITOR': 'code'}

env = ChainMap(session, user, system)

print("Environment:")
for key in ['EDITOR', 'SHELL', 'PAGER']:
    if key in env:
        print(f"  {key}: {env[key]}")

# Maps attribute
print("\nMaps attribute:")

dict1 = {'a': 1}
dict2 = {'b': 2}
dict3 = {'c': 3}

cm = ChainMap(dict1, dict2, dict3)

print(f"Maps: {cm.maps}")
print(f"First map: {cm.maps[0]}")
print(f"All maps: {cm.maps}")

# Modify maps
cm.maps[0]['d'] = 4
print(f"After modification: {dict(cm)}")

# Parents
print("\nParents:")

dict1 = {'a': 1}
dict2 = {'b': 2}
dict3 = {'c': 3}

cm = ChainMap(dict1, dict2, dict3)

print(f"Full chain: {dict(cm)}")
print(f"Parents (skip first): {dict(cm.parents)}")
print(f"Parents.parents: {dict(cm.parents.parents)}")

# Fallback values
print("\nFallback values:")

primary = {'name': 'Alice', 'age': 30}
fallback = {'name': 'Unknown', 'age': 0, 'city': 'Unknown'}

data = ChainMap(primary, fallback)

print(f"Name: {data['name']}")
print(f"Age: {data['age']}")
print(f"City: {data['city']}")  # From fallback

# Merge vs ChainMap
print("\nMerge vs ChainMap:")

d1 = {'a': 1, 'b': 2}
d2 = {'b': 3, 'c': 4}

# Merge (creates new dict)
merged = {**d1, **d2}
print(f"Merged: {merged}")

# ChainMap (no copy)
chained = ChainMap(d1, d2)
print(f"Chained: {dict(chained)}")

# Modify original
d1['a'] = 10

print(f"After modifying d1:")
print(f"Merged: {merged}")  # Unchanged
print(f"Chained: {dict(chained)}")  # Reflects change

  1. dict1 ← {'a': 1, 'b': 2}, dict2 ← {'b': 3, 'c': 4}, dict3 ← {'c': 5, 'd': 6}

    5# Basic ChainMap6print("Basic ChainMap:")78dict1→ {'a': 1, 'b': 2} = {'a': 1, 'b': 2}9dict2→ {'b': 3, 'c': 4} = {'b': 3, 'c': 4}10dict3→ {'c': 5, 'd': 6} = {'c': 5, 'd': 6}1112cm→ ChainMap({'a': 1, 'b': 2}, {'b': 3, 'c': 4}, {'c': 5, 'd': 6}) = ChainMap(dict1{'a': 1, 'b': 2}, dict2{'b': 3, 'c': 4}, dict3{'c': 5, 'd': 6})1314print(f"Dict1: {dict1{'a': 1, 'b': 2}}")15print(f"Dict2: {dict2{'b': 3, 'c': 4}}")16print(f"Dict3: {dict3{'c': 5, 'd': 6}}")17print(f"ChainMap: {dict(cmChainMap({'a': 1, 'b': 2}, {'b': 3, 'c': 4}, {'c': 5, 'd': 6}))}")1819# First occurrence wins20print(f"cm['a']: {cm['a']1}")  # From dict121print(f"cm['b']: {cm['b']2}")  # From dict122print(f"cm['c']: {cm['c']4}")  # From dict223print(f"cm['d']: {cm['d']6}")  # From dict32425# Configuration hierarchy26print("\nConfiguration hierarchy:")2728# Default config29defaults→ {'host': 'localhost', 'port': 8080, 'debug': False, 'timeout': 30} = {30    'host': 'localhost',31    'port': 8080,32    'debug': False,33    'timeout': 3034}3536# User config37user_config→ {'port': 9000, 'debug': True} = {38    'port': 9000,39    'debug': True40}4142# Command line args43cli_args→ {'host': '192.168.1.1'} = {44    'host': '192.168.1.1'45}4647# Priority: CLI > User > Defaults48config→ ChainMap({'host': '192.168.1.1'}, {'port': 9000, 'debug': True}, {'host': 'localhost', 'port': 8080, 'debug': False, 'timeout': 30}) = ChainMap(cli_args{'host': '192.168.1.1'}, user_config{'port': 9000, 'debug': True}, defaults{'host': 'localhost', 'port': 8080, 'debug': False, 'timeout': 30})4950print("Final config:")51for key in defaults.keys():
    outputBasic ChainMap:
    Dict1: {'a': 1, 'b': 2}
    Dict2: {'b': 3, 'c': 4}
    Dict3: {'c': 5, 'd': 6}
    ChainMap: {'c': 4, 'd': 6, 'b': 2, 'a': 1}
    cm['a']: 1
    cm['b']: 2
    cm['c']: 4
    cm['d']: 6
    
    Configuration hierarchy:
    Final config:
  2. for key in defaults.keys():

    pass 1 of 4
    50print("Final config:")51for keyhost in defaults{'host': 'localhost', 'port': 8080, 'debug': False, 'timeout': 30}.keys():52    print(f"  {keyhost}: {config[key]192.168.1.1}")
    output  host: 192.168.1.1
    All 4 passes — pass 1 is the card above
    passkeyconfig[key]
    1host192.168.1.1
    2port9000
    3debugTrue
    4timeout30
  3. dict1 ← {'a': 1}, dict2 ← {'b': 2}, cm ← ChainMap({'a': 1}, {'b': 2})

    54# Modifications55print("\nModifications:")5657dict1→ {'a': 1} = {'a': 1}58dict2→ {'b': 2} = {'b': 2}5960cm→ ChainMap({'a': 1}, {'b': 2}) = ChainMap(dict1{'a': 1}, dict2{'b': 2})61print(f"Original: {dict(cmChainMap({'a': 1}, {'b': 2}))}")6263# Update (modifies first dict)64cm['a']→ 10 = 1065cm['c']→ 3 = 36667print(f"After update: {dict(cmChainMap({'a': 10, 'c': 3}, {'b': 2}))}")68print(f"Dict1: {dict1{'a': 10, 'c': 3}}")  # Modified69print(f"Dict2: {dict2{'b': 2}}")  # Unchanged7071# New child72print("\nNew child:")7374base→ {'a': 1, 'b': 2} = {'a': 1, 'b': 2}75cm→ ChainMap({'a': 1, 'b': 2}) = ChainMap(base{'a': 1, 'b': 2})7677print(f"Base: {dict(cmChainMap({'a': 1, 'b': 2}))}")7879# Create new child context80cm→ ChainMap({'a': 10, 'c': 3}, {'a': 1, 'b': 2}) = cm.new_child({'a': 10, 'c': 3})81print(f"With child: {dict(cmChainMap({'a': 10, 'c': 3}, {'a': 1, 'b': 2}))}")8283# Can go back84cm→ ChainMap({'a': 1, 'b': 2}) = cm.parents→ ChainMap({})85print(f"Back to base: {dict(cmChainMap({'a': 1, 'b': 2}))}")8687# Scope simulation88print("\nScope simulation:")8990# Global scope91global_scope→ {'x': 10, 'y': 20} = {'x': 10, 'y': 20}9293# Function scope94def function():95    local_scope = {'x': 5, 'z': 30}96    scope = ChainMap(local_scope, global_scope)97    98    print(f"  x (local): {scope['x']}")99    print(f"  y (global): {scope['y']}")100    print(f"  z (local): {scope['z']}")101    102    return scope103104print("Inside function:")105function()
    output
    Modifications:
    Original: {'b': 2, 'a': 1}
    After update: {'b': 2, 'a': 10, 'c': 3}
    Dict1: {'a': 10, 'c': 3}
    Dict2: {'b': 2}
    
    New child:
    Base: {'a': 1, 'b': 2}
    With child: {'a': 10, 'b': 2, 'c': 3}
    Back to base: {'a': 1, 'b': 2}
    
    Scope simulation:
    Inside function:
  4. local_scope ← {'x': 5, 'z': 30}, scope ← ChainMap({'x': 5, 'z': 30}, {'x': 10, 'y': 20})

    93# Function scope94def function():95    local_scope→ {'x': 5, 'z': 30} = {'x': 5, 'z': 30}96    scope→ ChainMap({'x': 5, 'z': 30}, {'x': 10, 'y': 20}) = ChainMap(local_scope{'x': 5, 'z': 30}, global_scope{'x': 10, 'y': 20})97    98    print(f"  x (local): {scope['x']5}")99    print(f"  y (global): {scope['y']20}")100    print(f"  z (local): {scope['z']30}")101    102    return scopeChainMap({'x': 5, 'z': 30}, {'x': 10, 'y': 20})
    output  x (local): 5
      y (global): 20
      z (local): 30
  5. settings ← {'theme': 'light', 'font': 'Arial'}, temp ← ChainMap({'theme': 'dark'}, {'theme': 'light', 'font': 'Arial'})

    104print("Inside function:")105function()106107# Context managers108print("\nContext managers:")109110settings→ {'theme': 'light', 'font': 'Arial'} = {'theme': 'light', 'font': 'Arial'}111112print(f"Original: {settings{'theme': 'light', 'font': 'Arial'}}")113114# Temporary override115temp→ ChainMap({'theme': 'dark'}, {'theme': 'light', 'font': 'Arial'}) = ChainMap({'theme': 'dark'}, settings{'theme': 'light', 'font': 'Arial'})116print(f"Temporary: {dict(tempChainMap({'theme': 'dark'}, {'theme': 'light', 'font': 'Arial'}))}")117118# Original unchanged119print(f"Original: {settings{'theme': 'light', 'font': 'Arial'}}")120121# Environment variables122print("\nEnvironment variables:")123124# System defaults125system→ {'EDITOR': 'vi', 'SHELL': '/bin/sh'} = {'EDITOR': 'vi', 'SHELL': '/bin/sh'}126127# User preferences128user→ {'EDITOR': 'nano', 'PAGER': 'less'} = {'EDITOR': 'nano', 'PAGER': 'less'}129130# Current session131session→ {'EDITOR': 'code'} = {'EDITOR': 'code'}132133env→ ChainMap({'EDITOR': 'code'}, {'EDITOR': 'nano', 'PAGER': 'less'}, {'EDITOR': 'vi', 'SHELL': '/bin/sh'}) = ChainMap(session{'EDITOR': 'code'}, user{'EDITOR': 'nano', 'PAGER': 'less'}, system{'EDITOR': 'vi', 'SHELL': '/bin/sh'})134135print("Environment:")136for key in ['EDITOR', 'SHELL', 'PAGER']:
    output
    Context managers:
    Original: {'theme': 'light', 'font': 'Arial'}
    Temporary: {'theme': 'dark', 'font': 'Arial'}
    Original: {'theme': 'light', 'font': 'Arial'}
    
    Environment variables:
    Environment:
  6. for key in ['EDITOR', 'SHELL', 'PAGER']:

    pass 1 of 3
    135print("Environment:")136for keyEDITOR in ['EDITOR', 'SHELL', 'PAGER']:137    if key in env:138        print(f"  {key}: {env[key]}")
    All 3 passes — pass 1 is the card above
    passkey
    1EDITOR
    2SHELL
    3PAGER
  7. if key in env:

    pass 1 of 3
    136for key in ['EDITOR', 'SHELL', 'PAGER']:137    if keyEDITOR in envChainMap({'EDITOR': 'code'}, {'EDITOR': 'nano', 'PAGER': 'less'}, {'EDITOR': 'vi', 'SHELL': '/bin/sh'}):138        print(f"  {keyEDITOR}: {env[key]code}")
    output  EDITOR: code
    All 3 passes — pass 1 is the card above
    passkeyenv[key]
    1EDITORcode
    2SHELL/bin/sh
    3PAGERless
  8. dict1 ← {'a': 1}, dict2 ← {'b': 2}, dict3 ← {'c': 3}, cm ← ChainMap({'a': 1}, {'b': 2}, {'c': 3})

    140# Maps attribute141print("\nMaps attribute:")142143dict1→ {'a': 1} = {'a': 1}144dict2→ {'b': 2} = {'b': 2}145dict3→ {'c': 3} = {'c': 3}146147cm→ ChainMap({'a': 1}, {'b': 2}, {'c': 3}) = ChainMap(dict1{'a': 1}, dict2{'b': 2}, dict3{'c': 3})148149print(f"Maps: {cm.maps[{'a': 1}, {'b': 2}, {'c': 3}]}")150print(f"First map: {cm.maps[0]{'a': 1}}")151print(f"All maps: {cm.maps[{'a': 1}, {'b': 2}, {'c': 3}]}")152153# Modify maps154cm.maps[0]['d']→ 4 = 4155print(f"After modification: {dict(cmChainMap({'a': 1, 'd': 4}, {'b': 2}, {'c': 3}))}")156157# Parents158print("\nParents:")159160dict1→ {'a': 1} = {'a': 1}161dict2→ {'b': 2} = {'b': 2}162dict3→ {'c': 3} = {'c': 3}163164cm→ ChainMap({'a': 1}, {'b': 2}, {'c': 3}) = ChainMap(dict1{'a': 1}, dict2{'b': 2}, dict3{'c': 3})165166print(f"Full chain: {dict(cmChainMap({'a': 1}, {'b': 2}, {'c': 3}))}")167print(f"Parents (skip first): {dict(cm.parentsChainMap({'b': 2}, {'c': 3}))}")168print(f"Parents.parents: {dict(cm.parents.parentsChainMap({'c': 3}))}")169170# Fallback values171print("\nFallback values:")172173primary→ {'name': 'Alice', 'age': 30} = {'name': 'Alice', 'age': 30}174fallback→ {'name': 'Unknown', 'age': 0, 'city': 'Unknown'} = {'name': 'Unknown', 'age': 0, 'city': 'Unknown'}175176data→ ChainMap({'name': 'Alice', 'age': 30}, {'name': 'Unknown', 'age': 0, 'city': 'Unknown'}) = ChainMap(primary{'name': 'Alice', 'age': 30}, fallback{'name': 'Unknown', 'age': 0, 'city': 'Unknown'})177178print(f"Name: {data['name']Alice}")179print(f"Age: {data['age']30}")180print(f"City: {data['city']Unknown}")  # From fallback181182# Merge vs ChainMap183print("\nMerge vs ChainMap:")184185d1→ {'a': 1, 'b': 2} = {'a': 1, 'b': 2}186d2→ {'b': 3, 'c': 4} = {'b': 3, 'c': 4}187188# Merge (creates new dict)189merged→ {'a': 1, 'b': 3, 'c': 4} = {**d1{'a': 1, 'b': 2}, **d2{'b': 3, 'c': 4}}190print(f"Merged: {merged{'a': 1, 'b': 3, 'c': 4}}")191192# ChainMap (no copy)193chained→ ChainMap({'a': 1, 'b': 2}, {'b': 3, 'c': 4}) = ChainMap(d1{'a': 1, 'b': 2}, d2{'b': 3, 'c': 4})194print(f"Chained: {dict(chainedChainMap({'a': 1, 'b': 2}, {'b': 3, 'c': 4}))}")195196# Modify original197d1['a']→ 10 = 10198199print(f"After modifying d1:")200print(f"Merged: {merged{'a': 1, 'b': 3, 'c': 4}}")  # Unchanged201print(f"Chained: {dict(chainedChainMap({'a': 10, 'b': 2}, {'b': 3, 'c': 4}))}")  # Reflects change
    output
    Maps attribute:
    Maps: [{'a': 1}, {'b': 2}, {'c': 3}]
    First map: {'a': 1}
    All maps: [{'a': 1}, {'b': 2}, {'c': 3}]
    After modification: {'c': 3, 'b': 2, 'a': 1, 'd': 4}
    
    Parents:
    Full chain: {'c': 3, 'b': 2, 'a': 1}
    Parents (skip first): {'c': 3, 'b': 2}
    Parents.parents: {'c': 3}
    
    Fallback values:
    Name: Alice
    Age: 30
    City: Unknown
    
    Merge vs ChainMap:
    Merged: {'a': 1, 'b': 3, 'c': 4}
    Chained: {'b': 2, 'c': 4, 'a': 1}
    After modifying d1:
    Merged: {'a': 1, 'b': 3, 'c': 4}
    Chained: {'b': 2, 'c': 4, 'a': 10}
ChainMap Groups multiple dicts into a single view for lookups - useful for layered configurations like defaults, user settings, and command-line overrides.

Exercise: practical.py

Analyze word frequencies in text and group items by category