Key Takeaways: Dictionaries and Sets

One-Sentence Summary

Dictionaries map keys to values with O(1) average-case lookup, sets store unique elements with O(1) average-case membership testing, and choosing the right data structure is one of the most impactful decisions you'll make as a programmer.

Core Dictionary Operations

Operation Syntax What It Does
Create d = {"key": value} Create a dictionary with key-value pairs
Access d["key"] Get value (raises KeyError if missing)
Safe access d.get("key", default) Get value or return default if missing
Add/Update d["key"] = value Set a key-value pair
Delete del d["key"] Remove a key (raises KeyError if missing)
Delete (safe) d.pop("key", default) Remove and return value, or return default
Membership "key" in d Check if key exists (O(1))
Length len(d) Number of key-value pairs
Merge d1 \| d2 Merge two dicts (Python 3.9+)

Iteration Patterns

What You Need Method Loop Pattern
Just keys .keys() or default for key in d:
Just values .values() for val in d.values():
Both .items() for key, val in d.items():

The Frequency Counter Pattern

This is the most important dictionary pattern — memorize it:

counts = {}
for item in sequence:
    counts[item] = counts.get(item, 0) + 1

Or with Counter:

from collections import Counter
counts = Counter(sequence)

defaultdict(int) gives the same effect with plain += 1, and defaultdict(list) is the go-to for grouping items under a key.

Dictionary Comprehensions

{key_expr: value_expr for item in iterable if condition} builds a dict in one expression. For example, {name: s for name, s in scores.items() if s >= 70} keeps only passing scores. If the logic needs more than a line or two, a plain for loop reads better.

Set Operations at a Glance

Operation Operator What It Returns
Union a \| b Everything from both
Intersection a & b Only what's in both
Difference a - b In a but not in b
Symmetric difference a ^ b In one but not both

Choosing the Right Data Structure

Question Answer
"I need items in order, accessed by position" list
"I need an immutable sequence" tuple
"I need to look things up by a key/name" dict
"I need to check membership fast or remove duplicates" set
"I need to count things" dict or Counter
"I need to group items by a category" defaultdict(list)

Threshold Concept: Hash-Based O(1) Lookup

  • List search: O(n) — scan every element. 1 million items = up to 1 million checks.
  • Dict/set lookup: O(1) on average — compute the hash, jump to that slot. 1 million items takes about the same few steps as 10 items.
  • Keys must be hashable (immutable): strings, numbers, booleans, tuples whose contents are all hashable, frozensets.
  • Mutable objects (lists, dicts, sets) cannot be keys — use tuples instead.

Common Gotchas

  1. {} is an empty dict, not an empty set. Use set() for an empty set.
  2. in checks keys, not values. 3 in {"a": 3} is False.
  3. Don't add or remove keys while looping over a dict (RuntimeError). Loop over list(d) instead, or build a new dict with a comprehension.
  4. Keys are case-sensitive. d["Name"] and d["name"] are different keys.
  5. Sets have no reliable order. Converting a list to a set scrambles it; use list(dict.fromkeys(items)) to deduplicate while preserving order, and sorted(s) when you need to display a set predictably.

What's Next

Chapter 10: File I/O — save your dictionaries to JSON files, read data from CSV, and make your programs persistent.