Collections
Dictionaries
Key-Value Storage
You're building a phone book. Given a name, you need the phone number instantly. Lists require searching through every entry. Dictionaries give you direct lookup by key - O(1) instead of O(n).
Create a phone book
Store name-to-number associations.
phone_book.py
def main():
# Create a phone book dictionary
phone_book = {}
print("=== Building Phone Book ===")
# Add contacts
phone_book["Alice"] = "555-1234"
print(f"Added Alice: {phone_book}")
phone_book["Bob"] = "555-5678"
print(f"Added Bob: {phone_book}")
phone_book["Carol"] = "555-9999"
print(f"Added Carol: {phone_book}")
# Add more contacts
phone_book["David"] = "555-1111"
phone_book["Eve"] = "555-2222"
phone_book["Frank"] = "555-3333"
print(f"\nWith more contacts: {phone_book}")
print("\n=== Phone Book Contents ===")
print(f"Total contacts: {len(phone_book)}")
# Look up a number
name = "Bob"
number = phone_book[name]
print(f"\n{name}'s number: {number}")
# Display all contacts
print("\n=== All Contacts ===")
for name, number in phone_book.items():
print(f"{name}: {number}")
main()
{key: value} creates a dict. Use d[key] to access values.
dict
Key-value pairs with O(1) lookup. Keys must be unique and hashable.
Look up a contact
Retrieve a value by its key.
lookup.py
def main():
inventory = {
"Apples": 50,
"Bananas": 30,
"Oranges": 25,
"Grapes": 40
}
print("=== Store Inventory ===")
print(inventory)
# Look up existing item
item =
print("\n=== Inventory Lookup ===")
print(f"Looking for: {item}")
# UNSAFE: Direct access raises KeyError if missing!
# stock = inventory[item] # Would crash if item not found
# SAFE: Use .get() method
stock = inventory.get(item)
if stock is not None:
print(f"In stock: {stock} units")
if stock < 35:
print("⚠️ Low stock - consider reordering!")
else:
print("❌ Item not found in inventory!")
print(f"Available items: {list(inventory.keys())}")
# Using .get() with default value
print("\n=== Using .get() with default ===")
check_items = ["Apples", "Mangoes", "Oranges", "Pears"]
for check_item in check_items:
qty = inventory.get(check_item, 0) # 0 if not found
status = f"✓ {qty} in stock" if qty > 0 else "✗ Not available"
print(f"{check_item}: {status}")
main()
def main():
inventory = {
"Apples": 50,
"Bananas": 30,
"Oranges": 25,
"Grapes": 40
}
print("=== Store Inventory ===")
print(inventory)
# Look up existing item
item =
print("\n=== Inventory Lookup ===")
print(f"Looking for: {item}")
# UNSAFE: Direct access raises KeyError if missing!
# stock = inventory[item] # Would crash if item not found
# SAFE: Use .get() method
stock = inventory.get(item)
if stock is not None:
print(f"In stock: {stock} units")
if stock < 35:
print("⚠️ Low stock - consider reordering!")
else:
print("❌ Item not found in inventory!")
print(f"Available items: {list(inventory.keys())}")
# Using .get() with default value
print("\n=== Using .get() with default ===")
check_items = ["Apples", "Mangoes", "Oranges", "Pears"]
for check_item in check_items:
qty = inventory.get(check_item, 0) # 0 if not found
status = f"✓ {qty} in stock" if qty > 0 else "✗ Not available"
print(f"{check_item}: {status}")
main()
d[key] raises KeyError if missing. Use d.get(key) for safe access.
get
Safe lookup: `d.get(key)` returns None if missing. `d.get(key, default)` for default.
Update an entry
Change the value associated with a key.
update_entry.py
def main():
inventory = {
"Apples": 50,
"Bananas": 30,
"Oranges": 25
}
print("=== Initial Inventory ===")
print(inventory)
# Update: Restock apples
item = "Apples"
add_amount = 20
old_stock = inventory[item]
inventory[item] = old_stock + add_amount # Direct update
print("\n=== After Restocking ===")
print(f"{item}: {old_stock} → {inventory[item]}")
print(inventory)
# Sell some items
item = "Bananas"
sold = 5
inventory[item] -= sold
print(f"\nSold {sold} {item}")
print(inventory)
# Word frequency counter
print("\n=== Word Frequency Counter ===")
text = "apple banana apple orange apple banana grape"
words = text.split()
word_count = {}
for word in words:
# Get current count (0 if not seen), add 1
word_count[word] = word_count.get(word, 0) + 1
print(f'Text: "{text}"')
print(f"Word counts: {word_count}")
# Pythonic alternative: collections.Counter
from collections import Counter
print(f"Using Counter: {dict(Counter(words))}")
main()
d[key] = value updates if exists, adds if new.
Check if key exists
Test whether a key is in the dict before accessing.
check_key.py
def main():
user_passwords = {
"alice": "pass123",
"bob": "secret456",
"carol": "hunter2"
}
print("=== Login System ===")
print(f"Registered users: {list(user_passwords.keys())}")
# Login attempt
username =
password = "secret456"
print("\n=== Login Attempt ===")
print(f"Username: {username}")
# Check if user exists
if username in user_passwords:
print("✓ User found")
# Verify password
correct_password = user_passwords[username]
if correct_password == password:
print("✓ Password correct")
print("🎉 Login successful!")
else:
print("✗ Incorrect password")
else:
print("✗ User not found")
print("Would you like to register?")
# Check if value exists (less common)
print("\n=== Security Check ===")
weak_password = "pass123"
if weak_password in user_passwords.values():
print("⚠️ Someone is using a weak password!")
# Find which user (need to iterate)
for user, pwd in user_passwords.items():
if pwd == weak_password:
print(f"User with weak password: {user}")
main()
def main():
user_passwords = {
"alice": "pass123",
"bob": "secret456",
"carol": "hunter2"
}
print("=== Login System ===")
print(f"Registered users: {list(user_passwords.keys())}")
# Login attempt
username =
password = "secret456"
print("\n=== Login Attempt ===")
print(f"Username: {username}")
# Check if user exists
if username in user_passwords:
print("✓ User found")
# Verify password
correct_password = user_passwords[username]
if correct_password == password:
print("✓ Password correct")
print("🎉 Login successful!")
else:
print("✗ Incorrect password")
else:
print("✗ User not found")
print("Would you like to register?")
# Check if value exists (less common)
print("\n=== Security Check ===")
weak_password = "pass123"
if weak_password in user_passwords.values():
print("⚠️ Someone is using a weak password!")
# Find which user (need to iterate)
for user, pwd in user_passwords.items():
if pwd == weak_password:
print(f"User with weak password: {user}")
main()
key in d is O(1) - use it to avoid KeyError.
in
Membership test: `key in d`. Returns True/False in O(1) time.
Iterate through entries
Loop through keys, values, or key-value pairs.
iterate_dict.py
def main():
prices = {
"Coffee": 4.50,
"Tea": 3.00,
"Juice": 5.25,
"Water": 1.50,
"Soda": 2.75
}
print("=== Café Menu ===\n")
# Method 1: Iterate keys only
print("1. Keys only:")
for item in prices: # Or: prices.keys()
print(f" • {item}")
# Method 2: Iterate values only
print("\n2. Values only:")
total = 0
for price in prices.values():
total += price
print(f" ${price:.2f}")
print(f" Total: ${total:.2f}")
# Method 3: Iterate both with .items() - MOST COMMON
print("\n3. Keys and Values (.items()):")
for item, price in prices.items():
print(f" {item:<10} ${price:.2f}")
# Method 4: Enumerate with items (if you need index)
print("\n4. With index:")
for i, (item, price) in enumerate(prices.items(), 1):
print(f" {i}. {item}: ${price:.2f}")
# Find min and max priced items
print("\n=== Price Analysis ===")
# Pythonic: use min/max with key parameter
cheapest = min(prices, key=prices.get)
expensive = max(prices, key=prices.get)
print(f"Cheapest: {cheapest} (${prices[cheapest]:.2f})")
print(f"Most expensive: {expensive} (${prices[expensive]:.2f})")
# Average price
avg = sum(prices.values()) / len(prices)
print(f"Average price: ${avg:.2f}")
main()
Use d.keys(), d.values(), or d.items() for different views.
Exercise: dict_comprehension.py
Create dictionaries with comprehension syntax