Nested loops — comparing every pair
When you need to check every combination of two items, a nested loop is the straightforward (if slow) answer.
- Write a nested loop that visits every pair of items in a list
- Recognise when a brute-force nested loop is the right starting point
- Explain why nested loops are slow on large inputs (sets up Big-O for the intermediate tier)
The patterns in the previous two lessons — find, count, filter, transform — all share one property: a single pass through the list. Each item is visited once.
Sometimes that isn't enough. What if the question is "does any pair of numbers add up to 10?" or "are there any duplicate values?" To answer those, you need to compare each item against every other item. A single pass misses the combinations. You need a nested loop.
The mental model
Picture holding the first item in your left hand. With your right hand, you try every other item in the list to see if the pair satisfies your condition. Then you put the first item down, pick up the second, and repeat.
In code, the outer loop picks item A. The inner loop tries every possible item B:
for i in range(len(nums)): # outer loop: pick item A
for j in range(i + 1, len(nums)): # inner loop: try every item B after A
a, b = nums[i], nums[j]
# check the pair (a, b)Starting the inner loop at i + 1 (not 0) avoids comparing an item with
itself and avoids seeing the same pair twice — (a, b) and (b, a) are the
same pair.
Seeing every pair
Run it and count the pairs printed for a five-element list. Then try a six-element list. Notice how quickly the number of pairs grows.
Why nested loops are slow
With n items, the outer loop runs n times and the inner loop runs roughly
n times for each iteration of the outer loop. That's roughly n × n = n²
pairs total.
Think about what that means in practice. If your list has 100 items, you check about 5,000 pairs. If your list has 1,000 items, you check about 500,000 pairs. Double the list, quadruple the work. On a list of a million items, a nested loop might run for minutes.
This is intentional: the nested loop is the brute-force solution. It's worth reaching for first because it's obviously correct — every pair gets checked, nothing is missed. Once you have something correct, you can ask whether it's fast enough. The intermediate tier shows a technique that reduces many pair problems from n² to a single pass using a smarter data structure.
When to start here
The nested loop is the right starting point for any problem that requires examining combinations: "find any two items that …", "check whether some pair satisfies …", "collect all pairs where …". Once it works, then you think about whether there is a smarter approach.
Write has_pair_sum(nums, target) that returns True if any two different numbers in nums add up to target, and False otherwise.
has_pair_sum([1, 2, 3, 4], 7) → Truehas_pair_sum([1, 2, 3], 10) → FalseWhere to go next
You now have four building blocks — find, count, filter/transform, and nested loops. Head to the lab to put them together on fresh problems, then move on to the intermediate tier where you'll learn how to replace the slow nested loop with a fast single-pass approach.