Chapter 3: Strings and Loops / Lesson 22

Nested Loops

Understanding Nested Loops

A nested loop is a loop inside another loop. The inner loop completes all its iterations for each iteration of the outer loop. This creates a powerful pattern for working with multi-dimensional data, creating patterns, and solving complex problems.

Nested loops are essential when you need to process data that has multiple dimensions or when you need to generate combinations of values. They're commonly used for working with matrices, creating tables, generating patterns, and solving combinatorial problems.

Basic Nested For Loops

The most common nested loop pattern uses two for loops. The outer loop controls rows, while the inner loop controls columns:

basic_nested.py
# Simple nested loop structure for i in range(3): # Outer loop: runs 3 times (i = 0, 1, 2) for j in range(2): # Inner loop: runs 2 times for each i print(f"i={i}, j={j}") # Output: # i=0, j=0 # i=0, j=1 # i=1, j=0 # i=1, j=1 # i=2, j=0 # i=2, j=1 # Total: 3 Ɨ 2 = 6 iterations # Understanding the flow: outer loop runs once, inner loop completes all iterations for row in range(2): print(f"Row {row}:") for col in range(3): print(f" Column {col}", end=" ") print() # New line after each row

Multiplication Tables

Nested loops are perfect for creating multiplication tables and similar grid structures:

multiplication_table.py
# Create a 5x5 multiplication table print("Multiplication Table (5x5)") print("-" * 40) for i in range(1, 6): # Rows: 1 to 5 for j in range(1, 6): # Columns: 1 to 5 result = i * j print(f"{result:4d}", end="") # Format with width 4 print() # New line after each row # Output creates a neat 5x5 grid: # 1 2 3 4 5 # 2 4 6 8 10 # 3 6 9 12 15 # 4 8 12 16 20 # 5 10 15 20 25 # More formatted version with headers print("\nFormatted Table:") print(" ", end="") for j in range(1, 6): print(f"{j:4d}", end="") print() for i in range(1, 6): print(f"{i:2d}", end=" ") for j in range(1, 6): print(f"{i*j:4d}", end="") print()

Pattern Printing with Nested Loops

Nested loops excel at creating patterns and shapes. The outer loop controls rows, while the inner loop controls what's printed in each row:

patterns.py
# Pattern 1: Right triangle of stars for i in range(1, 6): for j in range(i): # Inner loop runs i times print("*", end="") print() # New line after each row # Output: # * # ** # *** # **** # ***** # Pattern 2: Inverted triangle for i in range(5, 0, -1): # Count down from 5 for j in range(i): print("*", end="") print() # Pattern 3: Pyramid with spaces for i in range(1, 6): # Print spaces for j in range(5 - i): print(" ", end="") # Print stars for j in range(2 * i - 1): print("*", end="") print() # Pattern 4: Number patterns for i in range(1, 6): for j in range(1, i + 1): print(j, end=" ") print()

Working with 2D Data Structures

Nested loops are essential for processing two-dimensional data like matrices or grids:

2d_data.py
# Processing a 2D list (matrix) matrix = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ] # Access each element for row in matrix: for element in row: print(element, end=" ") print() # Using indices for more control for i in range(len(matrix)): # Loop through rows for j in range(len(matrix[i])): # Loop through columns print(f"matrix[{i}][{j}] = {matrix[i][j]}") # Calculate sum of all elements total = 0 for row in matrix: for element in row: total += element print(f"Sum of all elements: {total}") # Find maximum value max_val = matrix[0][0] for row in matrix: for element in row: if element > max_val: max_val = element print(f"Maximum value: {max_val}")

Nested Loops with Conditions

You can combine nested loops with conditional statements for complex logic:

conditional_nested.py
# Print only even products for i in range(1, 6): for j in range(1, 6): product = i * j if product % 2 == 0: # Only print even products print(f"{i} Ɨ {j} = {product}") # Find pairs that sum to a target target = 10 numbers = [2, 4, 6, 8, 3, 5] print(f"\nPairs that sum to {target}:") for i in range(len(numbers)): for j in range(i + 1, len(numbers)): # Avoid duplicates if numbers[i] + numbers[j] == target: print(f"{numbers[i]} + {numbers[j]} = {target}") # Check for duplicate values in 2D list grid = [[1, 2, 3], [2, 3, 4], [3, 4, 5]] seen = [] for row in grid: for value in row: if value in seen: print(f"Duplicate found: {value}") else: seen.append(value)

Triple Nested Loops

You can nest loops multiple levels deep for three-dimensional data or more complex structures:

triple_nested.py
# 3D structure example cube = [ [[1, 2], [3, 4]], [[5, 6], [7, 8]] ] # Access each element in 3D structure for i in range(len(cube)): print(f"Layer {i}:") for j in range(len(cube[i])): for k in range(len(cube[i][j])): print(f" cube[{i}][{j}][{k}] = {cube[i][j][k]}") # Generate all combinations of three lists colors = ["red", "blue"] sizes = ["S", "M"] styles = ["plain", "striped"] print("\nAll combinations:") for color in colors: for size in sizes: for style in styles: print(f"{color} {size} {style}") # Total: 2 Ɨ 2 Ɨ 2 = 8 combinations

Nested While Loops

You can nest while loops, or mix for and while loops:

nested_while.py
# Nested while loops i = 1 while i <= 3: j = 1 while j <= 3: print(f"({i}, {j})", end=" ") j += 1 print() i += 1 # Mix for and while for i in range(1, 4): j = 1 while j <= i: # Inner loop runs while j <= i print("*", end="") j += 1 print() # Pattern: Print numbers in a decreasing triangle for i in range(5, 0, -1): counter = i while counter > 0: print(counter, end=" ") counter -= 1 print()

Break and Continue in Nested Loops

When using break and continue in nested loops, remember they only affect the innermost loop:

control_nested.py
# break in nested loops - only exits inner loop for i in range(1, 4): print(f"Row {i}:") for j in range(1, 5): if j == 3: break # Only breaks inner loop print(j, end=" ") print() # continue in nested loops for i in range(1, 4): for j in range(1, 4): if j == 2: continue # Skip j=2, continue with j=3 print(f"({i}, {j})", end=" ") print() # Breaking out of multiple nested loops using a flag found = False for i in range(5): if found: break for j in range(5): if i * j == 12: print(f"Found at ({i}, {j})") found = True break

Performance Considerations

Nested loops can quickly increase the number of iterations. Understanding this helps you write efficient code:

šŸ’” Time Complexity

• Two nested loops: O(n²) - if each loop runs n times, total iterations = n Ɨ n

• Three nested loops: O(n³) - n Ɨ n Ɨ n iterations

• Be careful with large datasets - nested loops can become slow

performance.py
# Count iterations to understand complexity count = 0 for i in range(10): for j in range(10): count += 1 print(f"Total iterations: {count}") # 100 iterations # Early exit can improve performance target = 50 found = False for i in range(100): if found: break for j in range(100): if i * j == target: print(f"Found at ({i}, {j})") found = True break # Saves many iterations

Practical Applications

Nested loops are used in many real-world scenarios:

applications.py
# Application 1: Comparing elements in lists list1 = ["apple", "banana", "cherry"] list2 = ["apple", "orange", "banana"] print("Common items:") for item1 in list1: for item2 in list2: if item1 == item2: print(item1) # Application 2: Grid-based games (like tic-tac-toe check) board = [ ["X", "O", "X"], ["O", "X", "O"], ["X", "O", "X"] ] print("\nBoard layout:") for row in board: for cell in row: print(cell, end=" | ") print() print("-" * 9) # Application 3: Data validation across dimensions grades = [ [85, 92, 78], [90, 88, 95], [75, 80, 85] ] # Check if all grades are passing (>= 70) all_passing = True for student_grades in grades: for grade in student_grades: if grade < 70: all_passing = False break if not all_passing: break print(f"\nAll passing: {all_passing}")

Best Practices and Tips

āœ… When to Use Nested Loops

• Working with 2D/3D data structures (matrices, grids)

• Generating combinations or permutations

• Creating patterns and visual displays

• Comparing elements across multiple collections

• Processing data with multiple dimensions

āš ļø Important Considerations

• Nested loops multiply the number of iterations - be mindful of performance

• Use descriptive variable names (i, j, k are fine, but row, col, depth are clearer)

• Consider if you can optimize with early exits (break) or skipping (continue)

• For very deep nesting (4+ levels), consider restructuring your code

• Python's list comprehensions can sometimes replace nested loops (advanced topic)

šŸ’” Variable Naming Tips

• Use meaningful names: row, col instead of i, j when it improves clarity

• For simple patterns, i, j, k are acceptable

• Inner loop variables can reference outer loop variables for clarity

Common Mistakes to Avoid

mistakes.py
# Mistake 1: Forgetting to reset inner loop variable # This creates an infinite loop! # i = 1 # while i <= 3: # j = 1 # Must reset j for each i # while j <= 3: # print(f"({i}, {j})") # j += 1 # i += 1 # Mistake 2: Using wrong variable in inner loop # for i in range(3): # for j in range(3): # print(i * i) # Wrong! Should be i * j # Mistake 3: Not understanding loop order # The outer loop controls the "big picture", inner loop handles details for row in range(3): # Process each row for col in range(3): # Process each column in that row print(f"Processing row {row}, col {col}")
šŸŽ‰

Lesson Complete!

Great work! Continue to the next lesson.

main.py
šŸ“¤ Output
Click "Run" to execute...