Optional: Nested Loops and Advanced Patterns
Learn nested loops in Python, when to use them, their performance impact, how to keep code readable, and explore better alternatives when possible.
Introduction
Sometimes you need to loop through lists inside other loops.
You have rooms organized by floor. You want to process every floor, and within each floor, every room.
Or you're comparing every sheet against every other sheet to find duplicates.
This is what nested loops do — loops inside loops.
But nested loops can make code slow and hard to read. This lesson shows you when they're necessary and when to avoid them.
Lesson Overview
This section contains a general overview of topics you will learn in this lesson.
- Writing nested loops
- When they're necessary
- Performance implications
- Keeping them readable
- Alternatives when possible
Basic Nested Loop
A nested loop is a loop inside another loop.
floors = [
["Office 1", "Office 2"],
["Office 3", "Office 4"],
["Office 5", "Conference"]
]
for floor in floors:
for room in floor:
print(room)
Output:
Office 1
Office 2
Office 3
Office 4
Office 5
Conference
The outer loop processes each floor. The inner loop processes each room in that floor.
How Nested Loops Work
floors = [
["A", "B"],
["C", "D"]
]
for floor in floors:
print(f"Floor: {floor}")
for room in floor:
print(f" Room: {room}")
Output:
Floor: ['A', 'B']
Room: A
Room: B
Floor: ['C', 'D']
Room: C
Room: D
Step by step:
- Outer loop: first floor
["A", "B"] - Inner loop: process "A", then "B"
- Outer loop: second floor
["C", "D"] - Inner loop: process "C", then "D"
Architectural Example: Rooms by Floor
building = [
["Storage", "Mechanical"],
["Lobby", "Reception", "Office 1"],
["Office 2", "Office 3", "Conference"]
]
floor_names = ["Basement", "Ground", "First"]
for i, rooms in enumerate(building):
print(f"{floor_names[i]}:")
for room in rooms:
print(f" - {room}")
print()
Output:
Basement:
- Storage
- Mechanical
Ground:
- Lobby
- Reception
- Office 1
First:
- Office 2
- Office 3
- Conference
The Performance Problem
Nested loops can get slow quickly.
# Outer loop: 100 items
# Inner loop: 100 items
# Total iterations: 100 × 100 = 10,000
for i in range(100):
for j in range(100):
# This runs 10,000 times
pass
If each loop has 1,000 items, you get 1,000,000 iterations. This is called O(n²) complexity — it grows exponentially.
Rule of thumb: Avoid nested loops when dealing with large datasets unless absolutely necessary.
When Nested Loops Are Necessary
Use Case 1: Hierarchical Data
When your data has natural layers or levels.
# Sheets organized by discipline
disciplines = {
"Architectural": ["A-101", "A-102", "A-201"],
"Structural": ["S-101", "S-102"],
"MEP": ["M-101", "E-101"]
}
for discipline, sheets in disciplines.items():
print(f"{discipline}:")
for sheet in sheets:
print(f" {sheet}")
Output:
Architectural:
A-101
A-102
A-201
Structural:
S-101
S-102
MEP:
M-101
E-101
Use Case 2: Comparing Items
When you need to compare each item against every other item.
sheets = ["A-101", "A-102", "A-101", "A-201"]
print("Finding duplicates:")
for i in range(len(sheets)):
for j in range(i + 1, len(sheets)):
if sheets[i] == sheets[j]:
print(f"Duplicate found: {sheets[i]}")
Output:
Finding duplicates:
Duplicate found: A-101
Use Case 3: Grid/Matrix Operations
When working with coordinates or 2D layouts.
# 3x3 grid of spaces
grid = [
["Office", "Office", "Meeting"],
["Office", "Open", "Office"],
["Storage", "Office", "Break"]
]
print("Grid Layout:")
for row_num, row in enumerate(grid):
for col_num, space in enumerate(row):
print(f"({row_num},{col_num}): {space}")
Keeping Nested Loops Readable
Use Descriptive Names
# Bad - unclear
for i in data:
for j in i:
print(j)
# Good - clear
for floor in building:
for room in floor:
print(room)
Limit Nesting Depth
Avoid more than 2-3 levels of nesting.
# Too deep (4 levels)
for building in campus:
for floor in building:
for wing in floor:
for room in wing:
# Hard to follow
pass
# Better - flatten or extract to functions
for building in campus:
for floor in building:
process_floor(floor) # Handle wings and rooms inside function
Add Comments for Complex Logic
floors = [["A", "B"], ["C", "D"]]
# Process each floor
for floor_num, rooms in enumerate(floors):
print(f"Floor {floor_num}:")
# Process each room on this floor
for room in rooms:
print(f" Room: {room}")
Alternatives to Nested Loops
Alternative 1: Flatten the Data
Instead of nested loops, flatten your data structure.
# Nested structure
floors = [
["Office 1", "Office 2"],
["Office 3", "Office 4"]
]
# Nested loop
for floor in floors:
for room in floor:
print(room)
# Flattened structure
all_rooms = ["Office 1", "Office 2", "Office 3", "Office 4"]
# Single loop
for room in all_rooms:
print(room)
If you don't need the floor grouping, flatten it.
Alternative 2: Use Dictionaries
When comparing or looking up values, dictionaries are faster than nested loops.
# Slow - nested loop
sheets = ["A-101", "A-102", "A-201"]
issued = ["A-101", "A-201"]
for sheet in sheets:
for issued_sheet in issued:
if sheet == issued_sheet:
print(f"{sheet} is issued")
# Fast - dictionary lookup
issued_set = set(issued)
for sheet in sheets:
if sheet in issued_set:
print(f"{sheet} is issued")
The second version is much faster for large lists.
Alternative 3: Extract to Functions
Move inner loops to separate functions.
# Hard to read
for floor in building:
for room in floor:
if room["area"] >= 400:
if room["height"] >= 2.7:
print(f"{room['name']}: Compliant")
# Clearer
def is_compliant(room):
return room["area"] >= 400 and room["height"] >= 2.7
for floor in building:
for room in floor:
if is_compliant(room):
print(f"{room['name']}: Compliant")
You'll learn functions in Module 06.
Real Architectural Workflows
Example 1: Multi-Floor Room Report
building = [
[{"name": "Storage", "area": 8.5}, {"name": "Mechanical", "area": 12.0}],
[{"name": "Lobby", "area": 45.0}, {"name": "Office 1", "area": 12.5}],
[{"name": "Office 2", "area": 15.3}, {"name": "Conference", "area": 32.0}]
]
floor_names = ["Basement", "Ground", "First"]
print("Building Room Report:")
print("=" * 60)
total_area = 0
total_rooms = 0
for floor_num, rooms in enumerate(building):
floor_area = 0
print(f"\\n{floor_names[floor_num]}:")
print("-" * 60)
for room in rooms:
print(f" {room['name']:20} {room['area']:6.1f}m²")
floor_area += room["area"]
total_rooms += 1
print(f" {'Floor Total:':20} {floor_area:6.1f}m²")
total_area += floor_area
print("\\n" + "=" * 60)
print(f"Building Total: {total_area:.1f}m² ({total_rooms} rooms)")
Example 2: Sheet Cross-Reference
sheets = ["A-101", "A-102", "A-201"]
referenced_sheets = ["A-101", "S-101", "A-201", "M-101"]
print("Sheet Reference Check:")
print("-" * 50)
missing_refs = []
# Check each referenced sheet
for ref_sheet in referenced_sheets:
found = False
# See if it exists in our sheet set
for sheet in sheets:
if ref_sheet == sheet:
found = True
break
if not found:
missing_refs.append(ref_sheet)
if missing_refs:
print("Missing sheets:")
for sheet in missing_refs:
print(f" - {sheet}")
else:
print("All referenced sheets exist")
# Output:
# Sheet Reference Check:
# --------------------------------------------------
# Missing sheets:
# - S-101
# - M-101
Note: This could be more efficient with a set:
sheet_set = set(sheets)
missing_refs = []
for ref_sheet in referenced_sheets:
if ref_sheet not in sheet_set:
missing_refs.append(ref_sheet)
Example 3: Room Pairing (Grid Layout)
# Simplified floor layout (3x3 grid)
layout = [
["Office", "Office", "Meeting"],
["Office", "Open", "Office"],
["Storage", "Office", "Break"]
]
print("Office Locations:")
print("-" * 40)
office_count = 0
for row_num, row in enumerate(layout):
for col_num, space_type in enumerate(row):
if space_type == "Office":
office_count += 1
print(f"Office {office_count}: Row {row_num}, Col {col_num}")
print(f"\\nTotal offices: {office_count}")
# Output:
# Office Locations:
# ----------------------------------------
# Office 1: Row 0, Col 0
# Office 2: Row 0, Col 1
# Office 3: Row 1, Col 0
# Office 4: Row 1, Col 2
# Office 5: Row 2, Col 1
#
# Total offices: 5
When NOT to Use Nested Loops
Don't Nest When You Can Filter
# Unnecessary nesting
floors = [["Office 1", "Storage"], ["Office 2", "Office 3"]]
for floor in floors:
for room in floor:
if "Office" in room:
print(room)
# Better - flatten first
all_rooms = []
for floor in floors:
all_rooms.extend(floor)
for room in all_rooms:
if "Office" in room:
print(room)
Don't Nest for Lookups
# Slow - O(n²)
sheets = ["A-101", "A-102", "A-201"]
issued = ["A-101", "A-201"]
for sheet in sheets:
for issued_sheet in issued:
if sheet == issued_sheet:
print(f"{sheet} is issued")
# Fast - O(n)
issued_set = set(issued)
for sheet in sheets:
if sheet in issued_set:
print(f"{sheet} is issued")
Assignment
<div class="lesson-content__panel" markdown="1">
- Create a new file called
nested_loops.py - Basic nested loop:
- Create:
floors = [["A", "B"], ["C", "D"], ["E", "F"]] - Use nested loops to print each room
- Label each floor
- Create:
- Room report by floor:
- Floors:
[["Office 1", "Office 2"], ["Office 3", "Conference"], ["Office 4", "Break Room"]] - Floor names:
["Ground", "First", "Second"] - Print formatted report with floor names
- Floors:
- Finding duplicates:
- List:
sheets = ["A-101", "A-102", "A-101", "A-201", "A-102"] - Use nested loops to find duplicates
- Print each duplicate once
- List:
- Grid processing:
- Create a 3x3 grid of room types
- Use nested loops with enumerate
- Print position and type for each
- Total area calculation:
- Calculate total area across all floors
- Count total rooms
- Compare efficiency:
- Create a list of 100 sheets
- Create a list of 50 "issued" sheets
- Find issued sheets using nested loop (time it mentally)
- Find issued sheets using set lookup
- See which is clearer
- Real scenario - Multi-floor validation:
- Building with rooms per floor
- Each room has name and area
- Check if any room is below 12m²
- Report which floor and which room
- Count total violations
Floors with room data:
[ [{"name": "Office 1", "area": 12.5}, {"name": "Office 2", "area": 15.3}], [{"name": "Conference", "area": 45.0}]]
</div>
Knowledge Check
The following questions are an opportunity to reflect on key topics in this lesson.
- <a class="knowledge-check-link" href="#basic-nested-loop">What is a nested loop?</a>
- <a class="knowledge-check-link" href="#the-performance-problem">Why can nested loops be slow?</a>
- <a class="knowledge-check-link" href="#when-nested-loops-are-necessary">When are nested loops necessary?</a>
- <a class="knowledge-check-link" href="#keeping-nested-loops-readable">How do you keep nested loops readable?</a>
- <a class="knowledge-check-link" href="#alternatives-to-nested-loops">What are alternatives to nested loops?</a>
- <a class="knowledge-check-link" href="#when-not-to-use-nested-loops">When should you avoid nested loops?</a>
Additional Resources
This section contains helpful links to related content. It isn't required, so consider it supplemental.
- Python's nested loop guide provides additional examples and performance analysis
- Big O notation explained covers algorithm complexity
- When to use nested loops discusses real-world scenarios