Data Structures · #6 of 11

Lists + Tuples

Ordered collections and essential methods

Why it matters

Lists are the default container for most problems. Tuples lock data safely.

The idea

Lists are flexible shelves; tuples are sealed boxes. Tuples are hashable (can be dict keys, set members), lists are not.

Try it

List basics — append, extend, slice, comprehension:

xs = [1, 2, 3]
xs.append(4)          # in place
xs.extend([5, 6])     # in place
xs += [7]             # in place too
print(xs)

# Comprehension — the Pythonic loop
squares = [x*x for x in xs if x % 2 == 0]
print(squares)
not loaded

Tuples are immutable, support unpacking, and can be dict keys:

origin = (0, 0)
def move(point, dx, dy):
  x, y = point        # unpacking
  return (x + dx, y + dy)

print(move(origin, 3, 4))

routes = { (0, 0): "home", (3, 4): "park" }
print(routes[(3, 4)])
not loaded

Sorting — in place vs return new:

words = ["apple", "Banana", "cherry"]
print(sorted(words))                      # case-sensitive
print(sorted(words, key=str.lower))       # case-insensitive
print(sorted(words, key=len, reverse=True))

# In place — returns None! (common bug)
words.sort()
print(words)
not loaded

List methods (complete essentials)

| Method | What it does | Example | | --- | --- | --- | | append(x) | add one item | nums.append(5) | | extend(iter) | add many | nums.extend([6,7]) | | insert(i,x) | add at index | nums.insert(1, 42) | | remove(x) | remove first match | nums.remove(2) | | pop(i) | remove by index | nums.pop() | | clear() | remove all | nums.clear() | | index(x) | find position | nums.index(3) | | count(x) | count value | nums.count(3) | | sort() | sort in place | nums.sort() | | reverse() | reverse in place | nums.reverse() | | copy() | shallow copy | nums.copy() |

List as stack / queue

A list makes a fine stack (append / pop off the end). For a fast queue, reach for collections.deque — popping from the front of a list is O(n):

from collections import deque
q = deque([1, 2, 3])
q.append(4)     # enqueue
q.popleft()     # dequeue — O(1)

Copy vs alias (important)

a = [1, 2, 3]
b = a          # alias — same list, mutations are shared
c = a.copy()   # new list — independent

Nested list trap

[[0] * 3] * 3 repeats the same inner row three times — mutating one mutates all:

grid = [[0] * 3] * 3   # WRONG: shared rows
grid = [[0] * 3 for _ in range(3)]  # correct: independent rows

Quick check

Mini drills

Do's and don'ts

Going deeper — complexity snapshot
  • Index access: O(1)
  • Append: O(1) amortized
  • Insert/remove at front: O(n)
  • Membership (x in lst): O(n)

Common mistakes

Key takeaways