SECTION 1
Historical Context & Motivation
From the very beginning of computing, programmers needed ways to repeat instructions. A single loop handles one-dimensional repetition — scanning through a list, counting up to a number, or reading lines from a file. But the real world is often two-dimensional: think of a chessboard, a spreadsheet, or pixels on a screen. To process every cell in a grid, early computer scientists realized they needed a loop running inside another loop — a nested loop.
1843 • Ada Lovelace's Algorithm
1957 • FORTRAN's DO Loops
1972 • C Language & Nested for Loops
1991 • Python's Readable for-in Loops
Today, nested loops remain one of the most fundamental patterns in programming. Whether you are rendering graphics, searching a table, or generating multiplication charts, the question is the same: how do you systematically visit every combination of two ranges? That is exactly what nested loops solve.
SECTION 2
Core Principles & Definitions
Before diving into code, let's nail down the key ideas that make nested loops work. If you already know how a single for loop works — iterating over a range of values and executing a body of code each time — then a nested loop is simply putting one loop inside the body of another.
Outer Loop
Inner Loop
Total Iterations
Indentation Matters
KEY TAKEAWAY
SECTION 3
Visual Explanation — How Nested Loops Traverse a Grid
The diagram below shows how a nested loop visits every cell in a 4-row by 5-column grid. The outer loop variable row steps through rows 0 to 3. For each row, the inner loop variable col steps through columns 0 to 4. The numbered labels inside each cell show the order of execution — notice that the traversal goes left to right across one row before dropping down to the next.
row index, and the inner loop sweeps through every col before the next row begins.The Python code that produces this traversal pattern is concise. The outer for row in range(4) creates four iterations (rows 0–3). Inside that loop, for col in range(5) creates five iterations (columns 0–4) for each row. The innermost statement — whatever you put at the double-indented level — runs 4 × 5 = 20 times total.
SECTION 4
How Nested Loops Execute — Step by Step
Understanding the exact order in which Python runs each line is critical. Let's trace through a small nested loop to see how the variables change. Consider this snippet:
Sample Code
for row in range(3):
for col in range(4):
print(f"({row},{col})", end=" ")
print() # newline after each rowWhen Python reaches the outer loop, it sets row = 0 and enters the body. The body contains the inner loop, which sets col = 0, prints (0,0), then sets col = 1, prints (0,1), and so on until col = 3. Once the inner loop exhausts its range, Python executes the print() to produce a newline. Then the outer loop increments to row = 1 and the inner loop starts all over again from col = 0.
TOTAL ITERATIONS
If the outer loop runs m times and the inner loop runs n times, the body of the inner loop executes m × n times. For our example: 3 × 4 = 12 prints.
| Outer Iteration (row) | Inner Iterations (col) | Output |
|---|---|---|
row = 0 | col = 0, 1, 2, 3 | (0,0) (0,1) (0,2) (0,3) |
row = 1 | col = 0, 1, 2, 3 | (1,0) (1,1) (1,2) (1,3) |
row = 2 | col = 0, 1, 2, 3 | (2,0) (2,1) (2,2) (2,3) |
Trace table showing variable values during each pass of the nested loop
Notice the key pattern: the inner loop's variable resets to its starting value every time the outer loop advances. This reset behavior is what allows nested loops to systematically cover every combination of row and column values, much like reading every word on every line of a page.
SECTION 5
Building Patterns with Nested Loops
One of the most common introductory exercises for nested loops is building text-based patterns — shapes made of characters like stars, numbers, or letters. These exercises train you to think about which variable controls rows, which controls columns, and how many characters appear on each row. Below is a visual breakdown of three classic patterns and the relationship between the loop variables and the output.
The key insight with the triangle pattern is that the inner loop's range depends on the outer loop's variable. When r = 0, the inner loop runs once (range(1)). When r = 3, it runs four times (range(4)). This dependency is what creates the growing shape. Once you understand this mechanism, you can build inverted triangles, diamonds, and other patterns by adjusting the relationship between the outer variable and the inner range.
SECTION 6
Worked Example — Processing a 2D Grid
Suppose you have a 3 × 4 grid of test scores stored as a list of lists (a 2D list). You need to find the highest score in the entire grid. Let's walk through the solution step by step.
Given Data
scores = [
[88, 72, 95, 61],
[79, 84, 90, 77],
[93, 68, 81, 85]
]Finding the Maximum Score in a 2D List
- 1
Step 1 — Initialize a tracking variable
Before the loops begin, create a variable to hold the highest score found so far. A safe choice is to set it to the first element:max_score = scores[0][0]. This gives usmax_score = 88.max_score = 88 - 2
Step 2 — Write the outer loop
The outer loop iterates over each row. Sincescoreshas 3 sublists, we writefor row in scores:. On the first pass,rowequals[88, 72, 95, 61]. - 3
Step 3 — Write the inner loop
Inside the outer loop, we iterate over each individual score:for score in row:. This gives us one score at a time. The inner loop processes all four elements of the current row before the outer loop moves to the next row. - 4
Step 4 — Compare and update
In the body of the inner loop, we check:if score > max_score: max_score = score. When the loop reaches 95 (row 0, col 2),max_scoreupdates to 95. It never gets replaced because no later score exceeds 95. - 5
Step 5 — Output the result
After both loops finish, print the result:print(f"Highest score: {max_score}"). The loops visited all 3 × 4 = 12 elements, so we are guaranteed to have found the true maximum.Highest score: 95
Complete Code
scores = [
[88, 72, 95, 61],
[79, 84, 90, 77],
[93, 68, 81, 85]
]
max_score = scores[0][0]
for row in scores:
for score in row:
if score > max_score:
max_score = score
print(f"Highest score: {max_score}")SECTION 7
Strengths, Limitations & Common Pitfalls
Nested loops are powerful, but they come with trade-offs. Knowing when to use them — and when to look for alternatives — is an important part of growing as a programmer.
| Strengths | Limitations / Pitfalls |
|---|---|
| Straightforward way to process grids, tables, and any two-dimensional data structure. | Runtime grows multiplicatively. A 1 000 × 1 000 grid means 1 000 000 iterations — which can slow down a program significantly. |
| Pattern is easy to read in Python thanks to clear indentation. | Using the wrong variable (e.g., typing the outer variable where the inner variable should go) is a very common bug that produces wrong results silently. |
| Can be extended to three or more levels of nesting for higher-dimensional data. | Deep nesting (3+ levels) makes code hard to read and maintain. Experienced programmers often refactor into functions. |
| Flexible — the inner range can depend on the outer variable for triangular or variable-width patterns. | Forgetting to reset an accumulator between outer iterations (e.g., a row total) is a frequent logic error. |
Weighing the benefits and common mistakes of nested loops
KEY TAKEAWAY
SECTION 8
Connection to Advanced Topics
Nested loops are your entry point into several more advanced programming concepts. Once you feel confident with two levels of nesting, you'll be ready to explore topics like list comprehensions (a compact Python syntax for building lists with nested iteration), two-dimensional arrays in data science libraries like NumPy, and algorithms that rely on nested iteration such as sorting algorithms (bubble sort, selection sort) and matrix operations.
| What You Know Now | Where It Leads |
|---|---|
| Nested for loops to traverse a 2D list | List comprehensions with nested expressions for concise data transformation |
| Printing star patterns row by row | Generating pixel art or manipulating image data pixel by pixel |
| Counting total iterations (m × n) | Analyzing algorithm efficiency using Big-O notation (O(n²)) |
| Processing a grid of scores | Working with Pandas DataFrames, NumPy arrays, and database query results |
How nested loop skills connect to future CS topics
You don't need to worry about these advanced topics right now. The important thing is that the mental model you build today — understanding how an inner loop fully completes for each step of an outer loop — transfers directly to every one of these future concepts. Master it here, and those later topics will feel much more approachable.
SECTION 9
Practice Problems
Question 1: CONCEPTUAL
Show answer
Question 2: BASIC CALCULATION
for i in range(6):
for j in range(3):
print("hello")Show answer
Question 3: INTERMEDIATE
Show answer
for r in range(1, 6):
for c in range(r):
print("*", end=" ")
print()
When r = 1, range(r) produces range(1), so one star prints. When r = 5, range(5) produces five iterations, so five stars print. The print() after the inner loop moves to a new line. The total stars printed are 1 + 2 + 3 + 4 + 5 = 15.Question 4: APPLIED
seats = [
[True, False, True, True],
[False, False, True, False],
[True, True, True, False]
]
Write a nested loop that counts the number of empty seats and prints the result.Show answer
empty_count = 0
for row in seats:
for seat in row:
if not seat:
empty_count += 1
print(f"Empty seats: {empty_count}")
The outer loop iterates through each row (a sublist). The inner loop checks each seat in that row. When a seat is False (not taken), the counter increments. After visiting all 3 × 4 = 12 seats, empty_count equals 5 because there are five False values in the grid.Question 5: CRITICAL THINKING
for r in range(1, 6):
for c in range(1, 6):
print(r * r, end="\t")
print()Show answer
for r in range(1, 6):
for c in range(1, 6):
print(r * c, end="\t")
print()
This is a very common nested loop mistake — accidentally using the outer variable where the inner variable belongs. A good debugging habit is to verify that every loop variable is actually used inside its loop body for its intended purpose.SUMMARY
Lesson Summary
Summary
A nested loop places one loop inside the body of another, allowing you to systematically process two-dimensional structures like grids, tables, and 2D lists. The outer loop controls one dimension (typically rows), while the inner loop controls the other (typically columns). The inner loop runs to completion for every single iteration of the outer loop, producing a total of outer_count × inner_count executions of the innermost body.
You can build text patterns (rectangles, triangles, number grids) by varying the inner loop's range. You can process 2D data by iterating over rows and then over elements within each row. Common pitfalls include mixing up the inner and outer variables, forgetting to reset accumulators between rows, and underestimating how quickly total iterations grow as grid dimensions increase. Mastering nested loops lays the groundwork for list comprehensions, sorting algorithms, and working with multi-dimensional data in future courses.