Loop Through Two Lists in Python

Learn how to loop through two or more lists in Python using zip(), enumerate(), range(), indexes, nested loops, and zip_longest() for lists with different lengths.

Published

Updated

Read time 8 min read

Reviewed byDeepak Prasad

Loop Through Two Lists in Python

When people search for how to loop through two lists in Python or iterate two lists at the same time, they almost always want the same thing: walk the same index on each list together—first with first, second with second. That is “parallel” in the sense of aligned rows, not multiple CPU cores. The built-in zip() function is the standard answer: it takes two or more lists (any iterables), advances them in lockstep, and yields tuples you can unpack in a for loop.

This guide explains zip() for two lists, adding enumerate() when you need positions, using range() and indexes when that fits better, handling different list lengths (including itertools.zip_longest()), extending to more than two lists, and small recipes such as building a dict, summing corresponding items, and comparing values. It also contrasts zip with nested loops so you do not accidentally write an all-pairs search when you only wanted aligned pairs.

For single-list basics, see Python list with examples. For for syntax, see Python for loop. For zip in general, see Python zip function. For “index plus value” on one sequence, see Python enumerate.

Tested on: Python 3.13.3; kernel 6.14.0-37-generic.


Loop through two lists using zip()

The zip built-in is the idiomatic way to loop through two lists (or any iterables) in parallel. Each iteration receives one element from each argument in the same order; the length of the walk is driven by the shortest input, which matters later when lengths differ. In Python 3, zip returns an iterator: memory stays lazy until you consume it, and you can unpack each tuple into readable names.

Unpacking keeps the body of the loop focused on meaning (“name” and “score”) instead of subscripts:

python
names = ["Ada", "Lin", "Kim"]
scores = [92, 88, 95]

for name, score in zip(names, scores):
    print(name, score)
Output

That prints three lines pairing each name with its score—the usual “python zip two lists” pattern in application code.


Loop through two lists with index using enumerate()

Sometimes you need the row number as well as the paired values—for logging, writing back to a third structure, or matching another table by position. Wrapping enumerate around zip gives you a zero-based index that stays in sync with each tuple from zip. The index counts successful pairings, not the original length of a longer list if zip truncated.

python
names = ["Ada", "Lin", "Kim"]
scores = [92, 88, 95]

for i, (name, score) in enumerate(zip(names, scores)):
    print(i, name, score)
Output

That prints 0 Ada 92, then 1 Lin 88, then 2 Kim 95. If you only needed an index on one list, the plain enumerate patterns in Python enumerate apply; here zip keeps two streams aligned.


Loop through two lists using range() and index

Indexing with range(len(...)) is the older style and stays useful when you must assign back into the lists by position, combine non-default stepping, or mix lists with other index-driven logic. The important detail is to bound the loop by the smaller length (or the length you intend to touch) so you never read past the end of the shorter list. For how range stop values work, see Python range.

python
xs = [1, 2, 3]
ys = [10, 20, 30]

for i in range(len(xs)):
    print(i, xs[i] + ys[i])
Output

That prints 0 11, 1 22, 2 33. If len(xs) != len(ys), use range(min(len(xs), len(ys))) or prefer zip / zip_longest so the control flow matches the data shape.


Loop through two lists with different lengths

Real data often has missing rows: one CSV has four keys and another has two labels. You must decide whether trailing items on the longer list should be ignored, surfaced with placeholders, or handled in a second pass.

What happens when zip() lists have different lengths

zip always stops when the shortest iterable is exhausted. Extra items on longer lists are not an error—they simply never reach your loop body, which is easy to miss in logs or tests.

python
a = [1, 2, 3, 4]
b = ["a", "b"]

for pair in zip(a, b):
    print(pair)
Output

That prints (1, 'a') and (2, 'b') only—values 3 and 4 are skipped unless you handle length explicitly.

Use itertools.zip_longest() for missing values

When every index of the longest list should be visited, use itertools.zip_longest. It pairs elements until all iterators are exhausted, filling shorter streams with a fillvalue you choose (or None by default). Pick a fill value that cannot collide with real data, or branch on None inside the loop.

python
import itertools

a = [1, 2, 3, 4]
b = ["a", "b"]

for pair in itertools.zip_longest(a, b, fillvalue="-"):
    print(pair)
Output

That yields four tuples, padding the shorter list with "-" after real values run out.


Loop through more than two lists

zip accepts any number of positional iterables. Each round produces one n-tuple aligned across all of them, still governed by the shortest sequence overall. That scales the same mental model from “two lists in Python” to three or more parallel columns—coordinates, RGB channels, or split CSV fields.

python
xs = [1, 2, 3]
ys = [10, 20, 30]
zs = [100, 200, 300]

for t in zip(xs, ys, zs):
    print(sum(t))
Output

That prints 111, 222, 333. The same shortest-sequence rule applies: one short list truncates the whole zip.


Create a dictionary from two lists

When one list is keys and another is values in the same order, dict(zip(keys, values)) builds a mapping in one expression—no manual index loop required. Keys must be unique (later duplicates overwrite earlier ones, same as any dict literal). For broader mapping rules, see Python dictionary.

python
keys = ["x", "y", "z"]
vals = [1, 2, 3]
print(dict(zip(keys, vals)))
Output

That prints {'x': 1, 'y': 2, 'z': 3}.


Add corresponding items from two lists

Elementwise math is a common follow-up: totals, deltas, or vector addition. A for loop with zip is clear; a list comprehension stays readable when the body is a single expression. Both walk the same pairs; comprehension builds a new list without mutating the inputs.

python
a = [1, 2, 3]
b = [4, 5, 6]
sums = [x + y for x, y in zip(a, b)]
print(sums)
Output

That prints [5, 7, 9].


Compare items from two lists

Equality checks, thresholds, or custom predicates are all the same shape: pull aligned pairs, then test. If you only need a single yes/no answer such as “are all aligned pairs equal?” you can combine a generator with all or any; see Python any() and all() for that style.

python
a = [1, 4, 9]
b = [1, 3, 9]

for i, (x, y) in enumerate(zip(a, b)):
    print(i, x == y)
Output

That prints 0 True, then 1 False, then 2 True on three lines (index followed by equality).


Nested loop vs zip(): important difference

A nested for over two lists visits the Cartesian product: every item from the first list paired with every item from the second—length roughly len(a) * len(b) iterations. zip visits at most min(len(a), len(b)) aligned pairs. Mixing these up is a frequent bug when someone says “compare two lists” but implements all-pairs logic by mistake.

python
xs = [1, 2]
ys = [10, 20]

pairs_zip = list(zip(xs, ys))
pairs_nested = [(x, y) for x in xs for y in ys]

print("zip", pairs_zip)
print("nested", pairs_nested)
Output

That prints zip [(1, 10), (2, 20)] and nested [(1, 10), (1, 20), (2, 10), (2, 20)].


Should you use parallel processing for list loops?

For aligned iteration with zip or indexes, work is already cheap and sequential; spinning up processes or threads rarely helps. Reserve multiprocessing or async for cases where each body step is genuinely expensive (heavy numeric kernels, blocking I/O) and you have profiled a bottleneck. This article’s “parallel lists” wording means iterate two lists simultaneously in the Python sense—row alignment—not automatic multi-core execution.


Common mistakes when looping through two lists

  • Assuming zip visits every element of the longer list; it truncates at the shortest unless you use zip_longest.
  • Using range(len(a)) when b is shorter and indexing b[i] without guarding the length; align bounds or use zip.
  • Confusing nested loops (all combinations) with zip (same-index pairs only).
  • Forgetting that zip in Python 3 returns an iterator—consume once, or wrap in list(zip(...)) if you need multiple passes or random access.

Python loop through lists quick reference table

Goal Pattern
Pair two lists for x, y in zip(a, b):
Index + two values for i, (x, y) in enumerate(zip(a, b)):
Manual index for i in range(min(len(a), len(b))):
Unequal length, pad itertools.zip_longest(a, b, fillvalue=...)
Three or more aligned for row in zip(a, b, c):
Keys + values → dict dict(zip(keys, vals))
All combinations nested loops or itertools.product

Summary

To loop through two lists in Python, start with zip() for aligned tuples, add enumerate() when you need a running index, and use range() plus subscripts when you mutate by position or need non-default stepping—always bound indexes by the shorter list unless you pad. Different lengths mean either accepting zip truncation or switching to itertools.zip_longest() with an explicit fillvalue. dict(zip(...)), sums, and comparisons are the same pairing idea with a small transformation after each step. Nested loops answer a different question (every combination), not row alignment. Multiprocessing is unrelated to everyday zip workflows unless each iteration is truly expensive and measured as such.


References


Frequently Asked Questions

1. How do you loop through two lists at the same time in Python?

Use zip(list_a, list_b) in a for loop; each iteration gets a tuple of matching elements from the same index until the shortest iterable is exhausted.

2. What happens if two lists have different lengths and I use zip()?

zip stops when the shortest list ends and silently ignores extra items on longer lists; use itertools.zip_longest with a fillvalue if every position must be visited.

3. How do I get the index while zipping two lists?

Write for i, (a, b) in enumerate(zip(xs, ys)) so i counts iterations and (a, b) is each aligned pair.

4. When should I use range(len(list)) instead of zip?

Use indexes when you must mutate positions in place, need different stride logic, or lists are not really parallel; prefer zip for read-only pairing because it is clearer and avoids length mistakes.
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive …