Utilities
Collections Module
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:
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}")
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']for candidate, count in results.most_common():
pass 1 of 345print(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 votesAll 3 passes — pass 1 is the card above pass candidatecount1 Alice 4 2 Bob 2 3 Charlie 1 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'for word, count in sorted(freq.items(), key=lambda x: x[1], reverse=Tr…
pass 1 of 5125print(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': 3All 5 passes — pass 1 is the card above pass wordcount1 the 3 2 and 2 3 cat 1 4 dog 1 5 bird 1 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()
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']for candidate, count in results.most_common():
pass 1 of 345print(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 votesAll 3 passes — pass 1 is the card above pass candidatecount1 Alice 4 2 Bob 2 3 Charlie 1 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'for word, count in sorted(freq.items(), key=lambda x: x[1], reverse=Tr…
pass 1 of 5125print(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': 3All 5 passes — pass 1 is the card above pass wordcount1 the 3 2 and 2 3 cat 1 4 dog 1 5 bird 1 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()
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']for candidate, count in results.most_common():
pass 1 of 345print(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 votesAll 3 passes — pass 1 is the card above pass candidatecount1 Alice 4 2 Bob 2 3 Charlie 1 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'for word, count in sorted(freq.items(), key=lambda x: x[1], reverse=Tr…
pass 1 of 5125print(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': 3All 5 passes — pass 1 is the card above pass wordcount1 the 3 2 and 2 3 cat 1 4 dog 1 5 bird 1 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]})")
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):counts[word] ← 1
pass 1 of 624words = ['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']25for wordapple in words['apple', 'banana', 'apple', 'cherry', 'banana', 'apple']:26 counts[word]→ 1 += 1All 6 passes — pass 1 is the card above pass wordcounts[word]1 apple 0 → 1 2 banana 0 → 1 3 apple 1 → 2 4 cherry 0 → 1 5 banana 1 → 2 6 apple 2 → 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:groups[student] ← {'Math'}
pass 1 of 544for 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 pass studentsubjectgroups[student]1 Alice Math set() → {'Math'} 2 Bob Science set() → {'Science'} 3 Alice English {'Math'} → {'Math', 'English'} 4 Charlie Math set() → {'Math'} 5 Bob Math {'Science'} → {'Math', 'Science'} print("Student subjects:")
47print("Student subjects:")48for student, subjects in groups.items():outputStudent subjects:for student, subjects in groups.items():
pass 1 of 347print("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 pass studentsubjects1 Alice {'Math', 'English'} 2 Bob {'Math', 'Science'} 3 Charlie {'Math'} 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:by_grade[student[’grade’]] ← ['Alice']
pass 1 of 562by_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 pass studentstudent[’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'] print("By grade:")
66print("By grade:")67for grade in sorted(by_grade.keys()):outputBy grade:for grade in sorted(by_grade.keys()):
pass 1 of 366print("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, CharlieAll 3 passes — pass 1 is the card above pass gradeby_grade[grade]1 A ['Alice', 'Charlie'] 2 B ['Bob', 'Eve'] 3 C ['David'] 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:graph[src] ← ['B']
pass 1 of 598for 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 pass srcdstgraph[src]1 A B [] → ['B'] 2 A C ['B'] → ['B', 'C'] 3 B D [] → ['D'] 4 C D [] → ['D'] 5 D E [] → ['E'] print("Graph edges:")
101print("Graph edges:")102for node, neighbors in sorted(graph.items()):outputGraph edges:for node, neighbors in sorted(graph.items()):
pass 1 of 4101print("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 pass nodeneighbors1 A ['B', 'C'] 2 B ['D'] 3 C ['D'] 4 D ['E'] 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:word_positions[word] ← [0]
pass 1 of 9111for 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 pass iwordword_positions[word]1 0 the [] → [0] 2 1 quick [] → [1] 3 2 brown [] → [2] 4 3 fox [] → [3] 5 4 jumps [] → [4] 6 5 over [] → [5] 7 6 the [0] → [0, 6] 8 7 lazy [] → [7] 9 8 dog [] → [8] 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:for word in sorted(word_positions.keys()):
pass 1 of 8115print("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 pass wordword_positions[word]1 brown [2] 2 dog [8] 3 fox [3] 4 jumps [4] 5 lazy [7] 6 over [5] 7 quick [1] 8 the [0, 6] 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:row ← [1, 0, 3]
pass 1 of 3143print("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 pass irow1 0 [1, 0, 3] 2 1 [0, 5, 0] 3 2 [7, 0, 0] 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]}try:
159regular = dict(dd)160try:161 regular['c'](empty).append(3)162except KeyError:except KeyError:
161 regular['c'].append(3)162except KeyError:163 print("KeyError on regular dict (expected)")outputKeyError on regular dict (expected)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:freq[n] ← 1
pass 1 of 10171for n1 in data[1, 2, 2, 3, 3, 3, 4, 4, 4, 4]:172 freq[n]→ 1 += 1All 10 passes — pass 1 is the card above pass nfreq[n]1 1 0 → 1 2 2 0 → 1 3 2 1 → 2 4 3 0 → 1 5 3 1 → 2 6 3 2 → 3 7 4 0 → 1 8 4 1 → 2 9 4 2 → 3 10 4 3 → 4 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:bar ← █
pass 1 of 4175print("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 pass numfreq[num]bar1 1 1 █ 2 2 2 ██ 3 3 3 ███ 4 4 4 ████
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)}")
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:dq ← deque([1], maxlen=3)
pass 1 of 759for 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 pass idq1 1 deque([], maxlen=3) → deque([1], maxlen=3) 2 2 deque([1], maxlen=3) → deque([1, 2], maxlen=3) 3 3 deque([1, 2], maxlen=3) → deque([1, 2, 3], maxlen=3) 4 4 deque([1, 2, 3], maxlen=3) → deque([2, 3, 4], maxlen=3) 5 5 deque([2, 3, 4], maxlen=3) → deque([3, 4, 5], maxlen=3) 6 6 deque([3, 4, 5], maxlen=3) → deque([4, 5, 6], maxlen=3) 7 7 deque([4, 5, 6], maxlen=3) → deque([5, 6, 7], maxlen=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:recent ← deque(['open'], maxlen=5)
pass 1 of 870for 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 pass actionrecent1 open deque([], maxlen=5) → deque(['open'], maxlen=5) 2 save deque(['open'], maxlen=5) → deque(['open', 'save'], maxlen=5) 3 edit deque(['open', 'save'], maxlen=5) → deque(['open', 'save', 'edit'], maxlen=5) 4 copy deque(['open', 'save', 'edit'], maxlen=5) → deque(['open', 'save', 'edit', 'copy'], maxlen=5) 5 paste deque(['open', 'save', 'edit', 'copy'], maxlen=5) → deque(['open', 'save', 'edit', 'copy', 'paste'], maxlen=5) 6 delete deque(['open', 'save', 'edit', 'copy', 'paste'], maxlen=5) → deque(['save', 'edit', 'copy', 'paste', 'delete'], maxlen=5) 7 undo deque(['save', 'edit', 'copy', 'paste', 'delete'], maxlen=5) → deque(['edit', 'copy', 'paste', 'delete', 'undo'], maxlen=5) 8 redo deque(['edit', 'copy', 'paste', 'delete', 'undo'], maxlen=5) → deque(['copy', 'paste', 'delete', 'undo', 'redo'], maxlen=5) queue ← deque([])
74# Queue operations75print("\nQueue operations:")7677queue→ deque([]) = deque()output Queue operations:queue ← deque(['A'])
pass 1 of 479# 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 pass itemqueue1 A deque([]) → deque(['A']) 2 B deque(['A']) → deque(['A', 'B']) 3 C deque(['A', 'B']) → deque(['A', 'B', 'C']) 4 D deque(['A', 'B', 'C']) → deque(['A', 'B', 'C', 'D']) queue ← deque(['B', 'C', 'D']), item ← A
pass 1 of 484# 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 pass queueitem1 deque(['A', 'B', 'C', 'D']) → deque(['B', 'C', 'D']) A 2 deque(['B', 'C', 'D']) → deque(['C', 'D']) B 3 deque(['C', 'D']) → deque(['D']) C 4 deque(['D']) → deque([]) D stack ← deque([])
89# Stack operations90print("\nStack operations:")9192stack→ deque([]) = deque()output Stack operations:stack ← deque([1])
pass 1 of 494# 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 pass itemstack1 1 deque([]) → deque([1]) 2 2 deque([1]) → deque([1, 2]) 3 3 deque([1, 2]) → deque([1, 2, 3]) 4 4 deque([1, 2, 3]) → deque([1, 2, 3, 4]) stack ← deque([1, 2, 3]), item ← 4
pass 1 of 499# 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 pass stackitem1 deque([1, 2, 3, 4]) → deque([1, 2, 3]) 4 2 deque([1, 2, 3]) → deque([1, 2]) 3 3 deque([1, 2]) → deque([1]) 2 4 deque([1]) → deque([]) 1 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:for word in words:
pass 1 of 4114words = ['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 pass worddq1 racecar — 2 hello deque(['e', 'l', 'l']) 3 madam — 4 python deque(['y', 't', 'h', 'o']) dq ← deque(['r', 'a', 'c', 'e', 'c', 'a', 'r'])
pass 1 of 4107def 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 pass sdq1 racecar deque(['r', 'a', 'c', 'e', 'c', 'a', 'r']) 2 hello deque(['h', 'e', 'l', 'l', 'o']) 3 madam deque(['m', 'a', 'd', 'a', 'm']) 4 python deque(['p', 'y', 't', 'h', 'o', 'n']) while len(dq) > 1:
pass 1 of 7108dq = deque(s.lower())109while len(dqdeque(['r', 'a', 'c', 'e', 'c', 'a', 'r'])) > 1:110 if dq.popleft() != dq.pop():111 return FalseAll 7 passes — pass 1 is the card above pass dq1 deque(['r', 'a', 'c', 'e', 'c', 'a', 'r']) 2 deque(['a', 'c', 'e', 'c', 'a']) 3 deque(['c', 'e', 'c']) 4 deque(['h', 'e', 'l', 'l', 'o']) 5 deque(['m', 'a', 'd', 'a', 'm']) 6 deque(['a', 'd', 'a']) 7 deque(['p', 'y', 't', 'h', 'o', 'n']) return True
111 return False112return Trueprint(f"'{word}': {is_palindrome(word)}")
115for word in words:116 print(f"'{wordracecar}': {is_palindrome(word)}")output'racecar': Trueif dq.popleft() != dq.pop():
pass 1 of 2109while len(dq) > 1:110 if dqdeque(['e', 'l', 'l']).popleft() != dq.pop():111 return False112return Trueprint(f"'{word}': {is_palindrome(word)}")
115for word in words:116 print(f"'{wordhello}': {is_palindrome(word)}")output'hello': Falsereturn True
111 return False112return Trueprint(f"'{word}': {is_palindrome(word)}")
115for word in words:116 print(f"'{wordmadam}': {is_palindrome(word)}")output'madam': Trueif dq.popleft() != dq.pop():
pass 2 of 2109while len(dq) > 1:110 if dqdeque(['y', 't', 'h', 'o']).popleft() != dq.pop():111 return False112return Trueprint(f"'{word}': {is_palindrome(word)}")
115for word in words:116 print(f"'{wordpython}': {is_palindrome(word)}")output'python': Falsebuffer ← deque([], maxlen=5)
118# Circular buffer119print("\nCircular buffer:")120121buffer→ deque([], maxlen=5) = deque(maxlen=5)output Circular buffer:buffer ← deque([0], maxlen=5)
pass 1 of 10123for 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 pass ibuffer1 0 deque([], maxlen=5) → deque([0], maxlen=5) 2 1 deque([0], maxlen=5) → deque([0, 1], maxlen=5) 3 2 deque([0, 1], maxlen=5) → deque([0, 1, 2], maxlen=5) 4 3 deque([0, 1, 2], maxlen=5) → deque([0, 1, 2, 3], maxlen=5) 5 4 deque([0, 1, 2, 3], maxlen=5) → deque([0, 1, 2, 3, 4], maxlen=5) 6 5 deque([0, 1, 2, 3, 4], maxlen=5) → deque([1, 2, 3, 4, 5], maxlen=5) 7 6 deque([1, 2, 3, 4, 5], maxlen=5) → deque([2, 3, 4, 5, 6], maxlen=5) 8 7 deque([2, 3, 4, 5, 6], maxlen=5) → deque([3, 4, 5, 6, 7], maxlen=5) 9 8 deque([3, 4, 5, 6, 7], maxlen=5) → deque([4, 5, 6, 7, 8], maxlen=5) 10 9 deque([4, 5, 6, 7, 8], maxlen=5) → deque([5, 6, 7, 8, 9], maxlen=5) if i >= 4:
pass 1 of 6124buffer.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 pass ibuffer1 4 deque([0, 1, 2, 3, 4], maxlen=5) 2 5 deque([1, 2, 3, 4, 5], maxlen=5) 3 6 deque([2, 3, 4, 5, 6], maxlen=5) 4 7 deque([3, 4, 5, 6, 7], maxlen=5) 5 8 deque([4, 5, 6, 7, 8], maxlen=5) 6 9 deque([5, 6, 7, 8, 9], maxlen=5) 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:window ← deque([1], maxlen=3)
pass 1 of 10136for 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 pass numwindow1 1 deque([], maxlen=3) → deque([1], maxlen=3) 2 2 deque([1], maxlen=3) → deque([1, 2], maxlen=3) 3 3 deque([1, 2], maxlen=3) → deque([1, 2, 3], maxlen=3) 4 4 deque([1, 2, 3], maxlen=3) → deque([2, 3, 4], maxlen=3) 5 5 deque([2, 3, 4], maxlen=3) → deque([3, 4, 5], maxlen=3) 6 6 deque([3, 4, 5], maxlen=3) → deque([4, 5, 6], maxlen=3) 7 7 deque([4, 5, 6], maxlen=3) → deque([5, 6, 7], maxlen=3) 8 8 deque([5, 6, 7], maxlen=3) → deque([6, 7, 8], maxlen=3) 9 9 deque([6, 7, 8], maxlen=3) → deque([7, 8, 9], maxlen=3) 10 10 deque([7, 8, 9], maxlen=3) → deque([8, 9, 10], maxlen=3) avg ← 2.0
pass 1 of 8137window.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.0All 8 passes — pass 1 is the card above pass windowavg1 deque([1, 2, 3], maxlen=3) 2.0 2 deque([2, 3, 4], maxlen=3) 3.0 3 deque([3, 4, 5], maxlen=3) 4.0 4 deque([4, 5, 6], maxlen=3) 5.0 5 deque([5, 6, 7], maxlen=3) 6.0 6 deque([6, 7, 8], maxlen=3) 7.0 7 deque([7, 8, 9], maxlen=3) 8.0 8 deque([8, 9, 10], maxlen=3) 9.0 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: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→ [] = []queue ← deque([]), node ← A
pass 1 of 7159while queuedeque(['A']):160 node→ A = queue→ deque([]).popleft()161 if node not in visited:All 7 passes — pass 1 is the card above pass queuenode1 deque(['A']) → deque([]) A 2 deque(['B', 'C']) → deque(['C']) B 3 deque(['C', 'D', 'E']) → deque(['D', 'E']) C 4 deque(['D', 'E', 'F']) → deque(['E', 'F']) D 5 deque(['E', 'F']) → deque(['F']) E 6 deque(['F', 'F']) → deque(['F']) F 7 deque(['F']) → deque([]) F visited ← {'A'}, order ← ['A'], queue ← deque(['B', 'C'])
pass 1 of 6160node = 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 pass nodegraph[node]visitedorderqueue1 A ['B', 'C'] set() → {'A'} [] → ['A'] deque([]) → deque(['B', 'C']) 2 B ['D', 'E'] {'A'} → {'A', 'B'} ['A'] → ['A', 'B'] deque(['C']) → deque(['C', 'D', 'E']) 3 C ['F'] {'A', 'B'} → {'C', 'A', 'B'} ['A', 'B'] → ['A', 'B', 'C'] deque(['D', 'E']) → deque(['D', 'E', 'F']) 4 D [] {'C', 'A', 'B'} → {'C', 'D', 'A', 'B'} ['A', 'B', 'C'] → ['A', 'B', 'C', 'D'] deque(['E', 'F']) 5 E ['F'] {'C', 'D', 'A', 'B'} → {'B', 'C', 'A', 'D', 'E'} ['A', 'B', 'C', 'D'] → ['A', 'B', 'C', 'D', 'E'] deque(['F']) → deque(['F', 'F']) 6 F [] {'B', 'C', 'A', 'D', 'E'} → {'B', 'C', 'A', 'D', 'F', 'E'} ['A', 'B', 'C', 'D', 'E'] → ['A', 'B', 'C', 'D', 'E', 'F'] deque(['F']) return order
166return order['A', 'B', 'C', 'D', 'E', 'F']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}")
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:self.cache ← OrderedDict(), self.capacity ← 3
54class LRUCache:55 def __init__(self⟨LRUCache A⟩, capacity3):56 self.cache→ OrderedDict() = OrderedDict()57 self.capacity→ 3 = capacity3cache ← ⟨LRUCache A⟩
72cache→ ⟨LRUCache A⟩ = LRUCache(3)73cache⟨LRUCache A⟩.put('a', 1)74cache.put('b', 2)self.cache[key] ← 1
pass 1 of 465def 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 pass keyvalueself.capacityself.cache[key]self.cache1 a 1 — 1 — 2 b 2 — 2 — 3 c 3 — 3 — 4 d 4 3 4 OrderedDict({'b': 2, 'c': 3, 'a': 1, 'd': 4}) → OrderedDict({'c': 3, 'a': 1, 'd': 4}) cache.put('a', 1)
72cache = LRUCache(3)73cache⟨LRUCache A⟩.put('a', 1)74cache⟨LRUCache A⟩.put('b', 2)75cache.put('c', 3)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}")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})def get(self, key):
59def get(self⟨LRUCache A⟩, keya):60 if key in self.cache:61 self.cache.move_to_end(key)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 Nonecache.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})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)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:for key, value in od.items():
pass 1 of 3118print("Forward:")119for keyfirst, value1 in odOrderedDict({'first': 1, 'second': 2, 'third': 3}).items():120 print(f" {keyfirst}: {value1}")output first: 1All 3 passes — pass 1 is the card above pass keyvalue1 first 1 2 second 2 3 third 3 print("Reverse:")
122print("Reverse:")123for key, value in reversed(od.items()):outputReverse:for key, value in reversed(od.items()):
pass 1 of 3122print("Reverse:")123for keythird, value3 in reversed(odOrderedDict({'first': 1, 'second': 2, 'third': 3}).items()):124 print(f" {keythird}: {value3}")output third: 3All 3 passes — pass 1 is the card above pass keyvalue1 third 3 2 second 2 3 first 1 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:for i, (name, description) in enumerate(tasks.items(), 1):
pass 1 of 4135print("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 systemAll 4 passes — pass 1 is the card above pass inamedescription1 1 setup Initialize system 2 2 process Process data 3 3 validate Validate results 4 4 cleanup Clean up resources 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:for action in actions:
pass 1 of 8147for 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 pass actionmax_recentrecent1 open — — 2 save — — 3 edit — — 4 copy — — 5 paste — — 6 open — OrderedDict({'open': True, 'save': True, 'edit': True, 'copy': True, 'paste': True}) → OrderedDict({'save': True, 'edit': True, 'copy': True, 'paste': True, 'open': True}) 7 delete 5 OrderedDict({'save': True, 'edit': True, 'copy': True, 'paste': True, 'open': True, 'delete': True}) → OrderedDict({'edit': True, 'copy': True, 'paste': True, 'open': True, 'delete': True}) 8 undo 5 OrderedDict({'edit': True, 'copy': True, 'paste': True, 'open': True, 'delete': True, 'undo': True}) → OrderedDict({'copy': True, 'paste': True, 'open': True, 'delete': True, 'undo': True}) recent[action] ← True
pass 1 of 7148if 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 pass max_recentrecent[action]recent1 — True — 2 — True — 3 — True — 4 — True — 5 — True — 6 5 True OrderedDict({'save': True, 'edit': True, 'copy': True, 'paste': True, 'open': True, 'delete': True}) → OrderedDict({'edit': True, 'copy': True, 'paste': True, 'open': True, 'delete': True}) 7 5 True OrderedDict({'edit': True, 'copy': True, 'paste': True, 'open': True, 'delete': True, 'undo': True}) → OrderedDict({'copy': True, 'paste': True, 'open': True, 'delete': True, 'undo': True}) print(f"After '{action}': {list(recent.keys())}")
155print(f"After '{actionopen}': {list(recentOrderedDict({'open': True}).keys())}")outputAfter 'open': ['open']print(f"After '{action}': {list(recent.keys())}")
155print(f"After '{actionsave}': {list(recentOrderedDict({'open': True, 'save': True}).keys())}")outputAfter 'save': ['open', 'save']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']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']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']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: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']recent ← OrderedDict({'edit': True, 'copy': True, 'paste': True, 'open': True, 'delete': True})
pass 1 of 2151recent[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)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']recent ← OrderedDict({'copy': True, 'paste': True, 'open': True, 'delete': True, 'undo': True})
pass 2 of 2151recent[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)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']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:for key, value in config.items():
pass 1 of 4168print("Config:")169for keyhost, valuelocalhost in configOrderedDict({'host': 'localhost', 'port': 8080, 'debug': True, 'timeout': 30}).items():170 print(f" {keyhost} = {valuelocalhost}")output host = localhostAll 4 passes — pass 1 is the card above pass keyvalue1 host localhost 2 port 8080 3 debug True 4 timeout 30 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:for key, value in config.items():
pass 1 of 4174print("\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 = TrueAll 4 passes — pass 1 is the card above pass keyvalue1 debug True 2 host localhost 3 port 8080 4 timeout 30
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
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:for key in defaults.keys():
pass 1 of 450print("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.1All 4 passes — pass 1 is the card above pass keyconfig[key]1 host 192.168.1.1 2 port 9000 3 debug True 4 timeout 30 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: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): 30settings ← {'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:for key in ['EDITOR', 'SHELL', 'PAGER']:
pass 1 of 3135print("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 pass key1 EDITOR 2 SHELL 3 PAGER if key in env:
pass 1 of 3136for 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: codeAll 3 passes — pass 1 is the card above pass keyenv[key]1 EDITOR code 2 SHELL /bin/sh 3 PAGER less 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 changeoutput 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