← Home

088. Zip()

Pair up multiple iterables and process them together

088. Zip()

He takes a RAM snapshot every 10 seconds. He wants to compare current RSS to the previous snapshot to detect spikes — processes that grew more than 50 MB.

He has two parallel lists: current and previous RSS values. He needs to pair them up.

current  = [620, 85, 310, 12]
previous = [400, 82, 308, 11]
names    = ["chrome", "python", "slack", "vim"]

# Pair up all three lists in one loop
for name, curr, prev in zip(names, current, previous):
    delta = curr - prev
    if delta > 50:
        print(f"SPIKE: {name} grew {delta} MB")
# → SPIKE: chrome grew 220 MB

Index arithmetic (previous[i], current[i]) works but clutters the intent. zip makes the parallel structure explicit.


💡 Fun fact: Python’s zip() is named after the action of a zipper — it interleaves elements from multiple sequences just like a zipper’s teeth interlock. The function exists in nearly every functional programming language under names like zip, zipWith, or transpose. Python 3 made zip() lazy (an iterator), unlike Python 2 where it built a full list immediately.

⚠️ Watch out: zip() silently stops at the shortest iterable. If your names list has 5 elements but scores has only 4, the 5th name is silently dropped with no error. Use itertools.zip_longest() if you need to detect length mismatches — it fills missing values with None instead of stopping early.

🤔 Think about it: zip(*pairs) is the inverse of zip(list_a, list_b) — it “unzips” a list of pairs back into two separate tuples. Why does Python use the same * unpacking operator for both “spread a list into arguments” and “transpose a matrix”? Is this a clever reuse of syntax or a potential source of confusion?

Learning objectives

  • Use zip() to iterate over two iterables in parallel
  • Unpack zipped pairs in a for loop
  • Use zip(*pairs) to unzip a list of tuples

Key concepts

  • zip
  • parallel iteration
  • unpacking
  • unzip

Try it

Concept detail

zip(a, b) combines two iterables into pairs, one from each at a time.

zip(["Alice", "Bob"], [95, 78])
# yields: ("Alice", 95), ("Bob", 78)

for name, score in zip(names, scores):
    print(f"{name}: {score}")

zip with 3 or more iterables: for a, b, c in zip(list1, list2, list3): …

zip stops at the shortest iterable: zip([1, 2, 3], [“a”, “b”]) # yields (1,“a”), (2,“b”) — stops at 2

Materialize as list of tuples: list(zip(names, scores)) # → [(“Alice”, 95), (“Bob”, 78)]

Unzip (transpose) a list of pairs: pairs = [(“Alice”, 95), (“Bob”, 78)] names, scores = zip(*pairs) # names = (“Alice”, “Bob”), scores = (95, 78)

WHY zip instead of range(len(…)): # Index arithmetic — clutters intent: for i in range(len(names)): print(names[i], scores[i])

# zip — reads like parallel iteration:
for name, score in zip(names, scores):
    print(name, score)

itertools.zip_longest fills missing values with a default instead of stopping early.

Solution

def make_report(names, scores):
    return [f"{name}: {score}" for name, score in zip(names, scores)]

def dot_product(v1, v2):
    return sum(a * b for a, b in zip(v1, v2))

def unzip_pairs(pairs):
    names, scores = zip(*pairs)
    return list(names), list(scores)

Tests

def test_make_report():
    result = make_report(["Alice", "Bob"], [95, 78])
    assert result[0] == "Alice: 95"
    assert result[1] == "Bob: 78"

def test_make_report_format():
    result = make_report(["Carol"], [88])
    # broken code gives "88: Carol" — name and score swapped
    assert result[0].startswith("Carol")

def test_dot_product():
    assert dot_product([1, 2, 3], [4, 5, 6]) == 32

def test_dot_product_unit():
    # [1,0] · [0,1] = 0 (orthogonal vectors)
    assert dot_product([1, 0], [0, 1]) == 0

def test_dot_product_identity():
    assert dot_product([3, 4], [3, 4]) == 25  # 9 + 16

def test_unzip_pairs():
    names, scores = unzip_pairs([("Alice", 95), ("Bob", 78)])
    assert list(names) == ["Alice", "Bob"]
    assert list(scores) == [95, 78]

def test_unzip_pairs_order():
    names, scores = unzip_pairs([("Zara", 100), ("Adam", 60)])
    assert names[0] == "Zara"
    assert scores[0] == 100

Resources