Walk lists side by side with zip
`zip` walks two or more lists in step, handing you one item from each. It stops at the shortest list, which is either convenient or a bug.
- Walk parallel lists with
for a, b in zip(xs, ys)instead of indexing withrange(len(…)) - Number items from 1 with
enumerate(items, start=1) - Know that
zipsilently stops at the shortest list, and usestrict=Trueor a length check when that would hide a bug
Data often arrives as parallel lists: one list of station names and another of the day's highs, where position 0 of one belongs with position 0 of the other. You could loop over range(len(stations)) and index both lists, but the index is only plumbing.
zip(a, b) hands you the pairs directly: (a[0], b[0]), then (a[1], b[1]), and so on. Unpack each pair in the for line. enumerate (see Loops & Iteration) works on any list too, and start=1 numbers from 1, the way people count.
Run each example to see what it prints. Running examples doesn't count toward progress.
stations = ["Great Falls Airport", "Boston Logan", "Atlanta Hartsfield"] highs = [6.7, 2.2, 15.6] for rank, (station, high) in enumerate(zip(stations, highs), start=1): print(f"{rank}. {station}: {high} C")
A spreadsheet export is the classic parallel case: one header row of column names, then rows of values in the same order. zip(header, row) pairs every name with its value, and dict(...) turns those pairs into a dictionary.
def rows_as_dicts(header, rows): return [dict(zip(header, row)) for row in rows] header = ["flight", "origin", "destination"] rows = [["UA2017", "LAS", "IAH"], ["MQ3443", "MCI", "MIA"]] for record in rows_as_dicts(header, rows): print(record)
zip stops as soon as any list runs out, without a word. If one list is shorter because data went missing, the extra items are silently dropped and every later result can be wrong. When the lists must match, pass strict=True: zip then raises ValueError the moment the lengths turn out to differ.
scheduled = [300, 305, 313] actual = [296, 312] for planned, arrived in zip(scheduled, actual, strict=True): print(arrived - planned)
When to use it: any time two lists are matched by position: names and scores, a header and a row, scheduled and actual times. Mistakes to avoid: indexing with range(len(…)) when zip says it directly; and trusting zip with lists that might differ in length. Check len yourself, or use strict=True and let the error stop the program.
for a, b in zip(xs, ys)walks parallel lists without an index;dict(zip(header, row))builds a record.enumerate(items, start=1)numbers from 1.zipstops silently at the shortest list. Usestrict=Trueor check lengths when a mismatch means bad data.- Next:
sortedwith a key, to order records by any field.