Previous | Tutorial index | Next

Tutorial 4: Nested Loops and Advanced Patterns

Learning Objective

Understand how to place loops inside other loops, visualize their execution flow, use them to solve complex problems (like matrix traversal and pattern printing), and recognize performance implications.

1. The Concept of Nested Loops

A nested loop is simply a loop inside another loop. Think of it as a clock:

The Golden Rule of Nested Loops: For each single iteration of the outer loop, the entire inner loop completes all its iterations from start to finish.

Real-World Analogy: The Restaurant Menu

Imagine you have a menu with 3 courses (Appetizer, Main, Dessert). For each course, you have 4 options. To list every possible 3-course meal combination, you'd use 3 nested loops. The outer loop picks the appetizer, the middle loop picks the main for that appetizer, and the inner loop picks the dessert for that main. The total number of combinations is 3 * 4 * 4 = 48.

2. Syntax and Execution Tracing

for i in range(1, 4): # Outer loop (runs 3 times: i = 1, 2, 3) print(f"Outer: {i}") for j in range(1, 4): # Inner loop (runs 3 times per outer iteration) print(f" Inner: {j}") print("---") # Runs after the inner loop finishes

Step-by-Step Trace:

  1. i = 1 → Print "Outer: 1". Enter inner loop.
  2. i = 2 → Print "Outer: 2". Enter inner loop (starts over at j=1).
  3. i = 3 → (same pattern).

Crucial Observation: The inner loop's counter (j) resets to its starting value (1) every time the outer loop advances. It does not remember its previous value (which was 3). This is a common point of confusion for beginners.

3. Classic Pattern Printing (Stars and Shapes)

Nested loops are the foundation for printing visual patterns in the console. The outer loop usually controls the rows, and the inner loop controls the columns.

Example 1: A Solid Rectangle (3 rows, 5 columns)

for row in range(3): # 3 rows for col in range(5): # 5 stars per row print("*", end="") # Print star, stay on same line print() # Move to the next line after the row ends

Output:

***** ***** *****

Example 2: A Right Triangle (Increasing Stars)

This requires the inner loop's range to depend on the outer loop's current value.

for row in range(1, 6): # row goes 1, 2, 3, 4, 5 for col in range(row): # col runs 0 to row-1 print("*", end="") print()

Output:

* ** *** **** *****

Example 3: A Pyramid (Centered)

This combines spaces and stars.

n = 5 for i in range(1, n+1): # Print spaces for j in range(n - i): print(" ", end="") # Print stars for k in range(2*i - 1): print("*", end="") print()

Output:

* *** ***** ******* *********

4. Iterating Over 2D Lists (Matrices)

Nested loops are essential for processing tabular data (lists of lists).

# A 3x3 matrix (grid) matrix = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ] # Sum all elements using nested loops total = 0 for row in matrix: # row is a list (e.g., [1, 2, 3]) for element in row: # element is each number total += element print(total) # Output: 45 # Access by index (row, column) for i in range(len(matrix)): # rows for j in range(len(matrix[i])): # columns print(f"matrix[{i}][{j}] = {matrix[i][j]}")

5. The Critical Rule: break and continue in Nested Loops

This is the most important rule to memorize: break and continue only affect the innermost loop they are directly written inside. They do not affect any outer loops.

for i in range(3): # Outer loop print(f"Row {i}:", end=" ") for j in range(5): # Inner loop if j == 3: break # This breaks ONLY the inner loop! print(j, end=" ") print() # This executes after the inner loop breaks.

Output:

Row 0: 0 1 2 Row 1: 0 1 2 Row 2: 0 1 2

How to break out of the OUTER loop from inside? Use a flag variable.

found = False for i in range(10): for j in range(10): if i * j == 42: # Found what we want print(f"Found at i={i}, j={j}") found = True break if found: # Check the flag to break the outer loop break

6. Performance Considerations (Big-O Basics)

Nested loops multiply the number of iterations.

What does this mean?

Best Practices:

7. Advanced Pattern: Cartesian Product (All Pairs)

Nested loops are used to generate all combinations between two sets.

colors = ["red", "blue"] sizes = ["S", "M", "L"] for color in colors: for size in sizes: print(f"{color} - {size}")

Output:

red - S red - M red - L blue - S blue - M blue - L

(This is exactly how clothing inventory works!)

8. Common Pitfalls

  1. Forgetting to Reset Inner Variables: If you define a variable inside the inner loop and try to use it after the loop, it will hold its last value.

    for i in range(3): for j in range(3): last_j = j print(f"After inner: {last_j}") # Prints 2 each time (the last j)
  2. Off-by-One in Pattern Printing: If you want a triangle with n rows, ensure the inner loop runs exactly row times or row+1 times. Always test with small n (like n=3) to verify.

  3. Using the Same Variable Name in Both Loops:

    for i in range(3): for i in range(3): # Reusing 'i' is confusing and overwrites! print(i) # This works in Python but is BAD practice. Use different names (row, col).
  4. break Surprises: Beginners often think break will stop all loops. It doesn't. Always remember the "innermost only" rule.

  5. Performance Paralysis: Don't use nested loops to search through a list if you can use in or .index() (which are optimized C-level operations).

📝 Quiz: Check Your Understanding

Q1: How many times does the line print("Hi") execute?

for x in range(4): for y in range(3): print("Hi")

a) 7 times
b) 12 times
c) 4 times
d) 3 times

Answer(B) 12

Q2: What is the output of this code?

for i in range(2, 5): for j in range(1, i): print(i, j)

a) (2,1), (3,1), (3,2), (4,1), (4,2), (4,3) b) (2,2), (3,3), (4,4) c) (1,2), (2,3), (3,4)

Answer(A)

Q3: (True/False) If you use break inside an inner loop, the outer loop also stops immediately.

AnswerFalse

Q4: What is the total number of iterations for for i in range(100): for j in range(100): pass? a) 200
b) 10,000
c) 100

Answer(B)

💻 In-Tutorial Coding Exercises

Exercise 1: Multiplication Table (Custom Range) Ask the user for a number n. Print the multiplication table for all numbers from 1 to n (like a 12x12 table, but variable size). Each row should show 1 x i, 2 x i, etc. Format it nicely with \t (tab) to align columns.

Solution
n = int(input("Size: ")) for i in range(1, n+1): for j in range(1, n+1): print(i*j, end="\t") print()

Exercise 2: Diagonal Pattern Print a 5x5 grid where the main diagonal (row == column) contains 1, and all other cells contain 0. Expected Output:

1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1

Hint: Use an if statement inside the nested loop.

Solution
size = 5 for r in range(size): for c in range(size): if r == c: print("1", end=" ") else: print("0", end=" ") print()

Exercise 3: Sum of Each Row Given matrix = [[2, 4, 6], [1, 3, 5], [9, 8, 7]], write nested loops to calculate and print the sum of each row individually.

Solution
matrix = [[2,4,6], [1,3,5], [9,8,7]] for row in matrix: row_sum = sum(row) print(f"Row sum: {row_sum}")

Exercise 4: Building a Flattened List Given nested = [[1, 2], [3, 4, 5], [6]], write nested loops to create a single flat list [1, 2, 3, 4, 5, 6].

Solution
nested = [[1,2], [3,4,5], [6]] flat = [] for sub in nested: for item in sub: flat.append(item) print(flat)

Exercise 5: Break the Inner Loop Write a nested loop that searches for the first number divisible by 7 in a 2D list grid = [[12, 15, 21], [14, 8, 9], [5, 7, 11]]. Print "Found at (row, col)" and use break to stop the inner loop, and a flag to stop the outer loop.

Solution
grid = [[12,15,21], [14,8,9], [5,7,11]] found = False for r, row in enumerate(grid): for c, val in enumerate(row): if val % 7 == 0: print(f"Found at ({r},{c})") found = True break if found: break

📚 Homework Questions

Question 1: The Right-Aligned Triangle Write a program that asks the user for a number n. Print a right-aligned triangle of stars with n rows. Example (n=5):

* ** *** **** *****
Sample Answer
n = int(input("n: ")) for i in range(1, n+1): print(" " * (n-i) + "*" * i)

Question 2: Transpose a Matrix Write a program that takes a 2D list matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] and produces its transpose (rows become columns, columns become rows). Print the transposed matrix. Expected Output:

[1, 4, 7] [2, 5, 8] [3, 6, 9]

(Hint: The number of rows in the transpose equals the number of columns in the original).

Sample Answer
matrix = [[1,2,3], [4,5,6], [7,8,9]] trans = [[matrix[r][c] for r in range(len(matrix))] for c in range(len(matrix[0]))] for row in trans: print(row)

Question 3: The Prime Number Sieve (Combination Logic) Write a program that finds all pairs (x, y) where x and y are numbers from 1 to 10, such that x + y is a prime number. Use nested loops and a helper function (or logic) to check primality. Print each pair. Example Output: (1,1)=2, (1,2)=3, (2,1)=3...

Sample Answer
def is_prime(n): if n < 2: return False for d in range(2, int(n**0.5)+1): if n % d == 0: return False return True for x in range(1, 11): for y in range(1, 11): if is_prime(x+y): print(f"({x},{y})")

Question 4: Multiplication Table with Conditional Coloring Create a 10x10 multiplication table (1 to 10). Instead of just numbers, if the product is even, print E; if odd, print O. Format it as a grid. Partial Output (first 3 rows):

E O E O E ... O E O E O ... E O E O E ...
Sample Answer
for i in range(1, 11): for j in range(1, 11): prod = i*j print("E" if prod%2==0 else "O", end=" ") print()

Question 5: The Diamond Pattern (Advanced Challenge) Write a program that prints a diamond shape for a given odd number n (e.g., n=5). Output for n=5:

* *** ***** *** *

(Hint: You need an increasing triangle, then a decreasing triangle. Use two separate sets of nested loops, or a single loop with a carefully crafted inner range).

Sample Answer
n = int(input("Odd n: ")) for i in range(1, n+1, 2): print(" " * ((n-i)//2) + "*" * i) for i in range(n-2, 0, -2): print(" " * ((n-i)//2) + "*" * i)

Congratulations! You have now mastered nested loops. You understand the cartesian product concept, matrix traversal, pattern generation, and the critical rules of break/continue within nested contexts. This is a huge step toward writing complex, data-driven programs!

Previous | Tutorial index | Next