Data Structures — Cheat Sheet
Python A–Z · 6 topics. Download the PDF or the Instagram carousel and share it.
Lists — Python's Workhorse
Lists are mutable, ordered, dynamic arrays — the data structure behind 80% of Python code, with slicing, in-place methods, and O(1) append but O(n) insert-at-front.
- ✓append/pop at the end: O(1); insert/pop at the front: O(n) — use deque for queues
- ✓sort() mutates and returns None; sorted() returns a new list
- ✓Slices copy: lst[:] shallow-copies, lst[::-1] reverses
- ✓[[0]*3]*3 shares one row object — use a comprehension for 2D grids
nums = [10, 20, 30, 40, 50] nums.append(60) # add at end O(1) nums.insert(0, 5) # add at front O(n) — shifts all! nums.remove(30) # delete by VALUE O(n) last = nums.pop() # remove & return last O(1) first = nums.pop(0) # remove first O(n) print(nums[1:3]) # slice [start:stop) print(nums[-2:]) # last two print(nums[::-1]) # reversed copy copy = nums[:] # shallow copy nums.sort() # in-place, returns None! sorted_copy = sorted(nums, reverse=True) # new list # Trap: result = nums.sort() -> result is None matrix = [[0] * 3 for _ in range(3)] # correct 3x3 bad = [[0] * 3] * 3 # 3 references to SAME row!
Tuples — Immutable Sequences & Unpacking
Tuples are immutable, ordered sequences — used for fixed records, multiple return values, dict keys, and elegant unpacking.
- ✓Tuples are immutable and hashable — usable as dict/set keys (lists are not)
- ✓(5,) is a tuple; (5) is just the int 5 — the comma matters
- ✓return a, b returns a tuple; unpacking works everywhere (loops, swaps, star-unpacking)
- ✓Immutability is shallow — a tuple containing a list allows the list to change
point = (3, 4)
person = "Asha", 24, "Pune" # parens optional
single = (5,) # comma makes it a tuple!
x, y = point # unpacking
name, age, city = person
# Tuples as dict keys — grid problems!
visited = {}
visited[(0, 0)] = True
visited[(2, 3)] = True
print((2, 3) in visited) # True — O(1)
# Immutable = safe to share
# point[0] = 99 -> TypeError
# but: a tuple holding a LIST allows mutating the list
t = (1, [2, 3])
t[1].append(4) # legal! tuple holds same list ref
print(t) # (1, [2, 3, 4])Dictionaries — Hash Maps Done Right
Dicts are Python's hash maps: O(1) average lookup, insertion-ordered since 3.7, with get/setdefault patterns that eliminate KeyError boilerplate.
- ✓Average O(1) get/set/delete/contains; keys must be hashable
- ✓Insertion order preserved since Python 3.7 (guaranteed, not an accident)
- ✓freq[k] = freq.get(k, 0) + 1 and setdefault(k, []).append(v) — memorize both idioms
- ✓Merge: {**a, **b} or a | b — right-most wins duplicate keys
marks = {"dsa": 85, "java": 90}
print(marks["dsa"]) # 85
# print(marks["sql"]) # KeyError!
print(marks.get("sql")) # None — safe
print(marks.get("sql", 0)) # 0 — with default
# Frequency count — THE interview idiom
freq = {}
for ch in "engineering":
freq[ch] = freq.get(ch, 0) + 1
print(freq) # {'e': 2, 'n': 3, 'g': 2, 'i': 2, 'r': 1}
# Grouping with setdefault
by_dept = {}
for name, dept in [("Asha", "CS"), ("Ravi", "IT"), ("Neha", "CS")]:
by_dept.setdefault(dept, []).append(name)
print(by_dept) # {'CS': ['Asha', 'Neha'], 'IT': ['Ravi']}
del marks["java"] # remove
score = marks.pop("dsa", 0) # remove & return (with default)Sets — Uniqueness & O(1) Membership
Sets store unique, unordered, hashable elements with O(1) membership tests and algebra operators (| & - ^) — the tool for dedupe, "seen" tracking, and intersection problems.
- ✓O(1) average add/remove/contains; elements must be hashable; no order
- ✓{} is an empty dict — use set() for an empty set
- ✓The seen-set pattern converts O(n²) scans into O(n)
- ✓& | - ^ solve common/missing-element questions in one line
emails = ["a@x.com", "b@x.com", "a@x.com"]
unique = set(emails) # {'a@x.com', 'b@x.com'}
print(len(emails) != len(unique)) # True -> duplicates exist
# O(1) membership vs list's O(n)
blocked = {"spam@x.com", "bot@x.com"}
if "spam@x.com" in blocked: # O(1)
print("blocked")
# Two Sum with a seen-set — O(n)
def two_sum_exists(nums, target):
seen = set()
for n in nums:
if target - n in seen:
return True
seen.add(n)
return False
print(two_sum_exists([3, 8, 1, 9], 10)) # True (1+9)
s = set() # empty set — {} is an empty DICT!
s.add(5); s.discard(99) # discard never raises; remove() doesComprehensions — Lists, Dicts, Sets & Generator Expressions
Comprehensions build collections declaratively — [x*2 for x in nums if x > 0] — replacing 4-line loops with one readable line, with dict/set variants and lazy generator expressions.
- ✓Order: expression → for → if(filter); if/else before the for is a value expression
- ✓Dict: {k: v for ...}; set: {x for ...}; generator: (x for ...)
- ✓Generator expressions are lazy and one-shot — perfect inside sum/any/all/max
- ✓Two clauses max for readability — beyond that, write the loop
nums = [3, -1, 8, -5, 12]
positives_doubled = [n * 2 for n in nums if n > 0] # [6, 16, 24]
# if/else as VALUE (before for) vs if as FILTER (after)
labels = ["pos" if n > 0 else "neg" for n in nums]
evens = [n for n in nums if n % 2 == 0]
# Dict & set comprehensions
squares = {n: n * n for n in range(5)}
lengths = {len(w) for w in ["go", "py", "java"]} # {2, 4}
inverted = {v: k for k, v in {"a": 1, "b": 2}.items()}
# Flatten a matrix — nested fors read left to right
matrix = [[1, 2], [3, 4], [5, 6]]
flat = [x for row in matrix for x in row] # [1,2,3,4,5,6]
# Same as:
# for row in matrix:
# for x in row: ...Mutability, Shallow Copy & Deep Copy
Assignment shares, copy() duplicates one level, deepcopy() duplicates everything — knowing which you need prevents the most common "my data changed by itself" bugs.
- ✓Assignment NEVER copies — it binds another name to the same object
- ✓Shallow copy (copy(), [:], list()) duplicates one level; deepcopy() recurses
- ✓Python is pass-by-object-reference: callees can mutate, not rebind, your objects
- ✓Immutables (int, str, tuple, frozenset) are immune to all of this — a reason to prefer them
import copy
teams = [["asha", "ravi"], ["neha"]]
alias = teams # level 0: same object
shallow = teams.copy() # level 1: new list, same inner lists
deep = copy.deepcopy(teams) # level 2: everything new
teams[1].append("kiran") # mutate a NESTED list
print(alias[1]) # ['neha', 'kiran'] — same object, obviously
print(shallow[1]) # ['neha', 'kiran'] — SHALLOW shares inner lists!
print(deep[1]) # ['neha'] — deep copy unaffected
# Shallow copy spellings (equivalent):
a = teams.copy(); b = teams[:]; c = list(teams)
# For flat lists of immutables, shallow is all you need
nums = [1, 2, 3]
safe = nums.copy()
safe.append(4) # nums untouched