Cheat SheetsPython A–ZData Structures

Data Structures — Cheat Sheet

Python A–Z · 6 topics. Download the PDF or the Instagram carousel and share it.

Cheat Sheet · AiCanCode.org
Data Structures
Python A–Z6 topicsQuick revision reference
1

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
Operations with their complexity
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!
2

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
Records, coordinate keys, the nested-mutable nuance
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])
3

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
get / setdefault — counting and grouping
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)
4

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
The seen-set — an interview superpower
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() does
5

Comprehensions — 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
All four comprehension forms
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: ...
6

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
Where shallow copy surprises you: nesting
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
Learn this free with Aria, your AI tutor → AiCanCode.org/learn/python