0%

20- Loop Magic & Iteration Patterns

Master the art of iteration. Parallel looping, reversing, sorting, filtering, and more. Patterns that make your loops elegant and powerful.

You know the basic for loop. You iterate over a list, a string, or a range. But the real power of iteration emerges when you learn the patterns. These are tricks and techniques that turn simple loops into elegant solutions. Do you need to loop through two lists at the same time? Use zip(). Need the index along with the value? Use enumerate(). Want to loop in reverse? Use reversed(). Need to skip items? Use conditions or itertools. This lesson covers the most useful iteration patterns. Master these, and you will write cleaner, faster, more Pythonic code.

🕯️ Magic Note

The functions enumerate(), zip(), reversed(), and sorted() all return iterators. They do not create new lists in memory. They generate values one at a time as you loop. This makes them memory efficient even for very large data.

Pattern 1: Looping with Index Using enumerate()
You need both the item and its position. Do not use range(len(list)). Use enumerate().

Python

fruits = [“apple”, “banana”, “cherry”, “date”]

# Bad way (C-style)

for i in range(len(fruits)):

print(f”{i}: {fruits[i]}”)

# Pythonic way

for i, fruit in enumerate(fruits):

print(f”{i}: {fruit}”)

# Start index from 1 instead of 0

for i, fruit in enumerate(fruits, start=1):

print(f”{i}: {fruit}”)

# 1: apple

# 2: banana

# 3: cherry

# 4: date

💡 enumerate() is cleaner, faster, and less error-prone than range(len()). Always prefer it when you need indices.
Pattern 2: Looping Through Multiple Lists with zip()
You have two or more lists. You want to process corresponding elements together. Use zip().

Python

names = [“Ali”, “Sara”, “Reza”, “Mina”]

scores = [95, 87, 92, 88]

ages = [25, 30, 28, 24]

# Loop through two lists

for name, score in zip(names, scores):

print(f”{name}: {score}”)

# Loop through three lists

for name, score, age in zip(names, scores, ages):

print(f”{name} | Score: {score} | Age: {age}”)

# Create a dictionary from two lists

name_score_dict = dict(zip(names, scores))

print(name_score_dict)

# {“Ali”: 95, “Sara”: 87, “Reza”: 92, “Mina”: 88}

⚠️ zip() stops at the shortest list. If your lists have different lengths, use itertools.zip_longest() with a fill value.

Python

from itertools import zip_longest

names = [“Ali”, “Sara”, “Reza”]

scores = [95, 87]

# zip() stops at shorter list

for name, score in zip(names, scores):

print(name, score) # Only prints Ali and Sara

# zip_longest fills missing values

for name, score in zip_longest(names, scores, fillvalue=0):

print(name, score) # Reza gets 0

Pattern 3: Looping in Reverse with reversed()
Sometimes you need to go backwards. Use reversed(). It works on any sequence.

Python

colors = [“red”, “green”, “blue”, “yellow”]

# Loop in reverse order

for color in reversed(colors):

print(color)

# yellow

# blue

# green

# red

# reverse with enumerate (get index from the end)

for i, color in enumerate(reversed(colors)):

print(f”{len(colors) – i – 1}: {color}”)

🕯️ Magic Note

reversed() does not create a new list. It returns an iterator that traverses the original list backwards. This is memory efficient.

Pattern 4: Looping in Sorted Order with sorted()
Need to iterate over items in sorted order without changing the original? Use sorted().

Python

numbers = [5, 2, 8, 1, 9, 3]

names = [“Sara”, “Ali”, “Reza”, “Mina”]

# Loop in ascending order

for num in sorted(numbers):

print(num, end=” “)

# 1 2 3 5 8 9

# Loop in descending order

for num in sorted(numbers, reverse=True):

print(num, end=” “)

# 9 8 5 3 2 1

# Sort strings alphabetically

for name in sorted(names):

print(name)

# Ali

# Mina

# Reza

# Sara

# Original list remains unchanged

print(numbers) # [5, 2, 8, 1, 9, 3] (still original order)

💡 Use sorted() when you need a temporary sorted view. Use .sort() when you want to permanently sort the list in place.
Pattern 5: Looping with Conditions (Filtering)
You only want to process items that meet a condition. Use if inside the loop.

Python

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

# Loop through even numbers only

for num in numbers:

if num % 2 == 0:

print(num, end=” “)

# 2 4 6 8 10

# Using filter() function (functional style)

for num in filter(lambda x: x % 2 == 0, numbers):

print(num, end=” “)

# 2 4 6 8 10

🕯️ Magic Note

List comprehensions can also filter. Write [x for x in numbers if x % 2 == 0] to create a filtered list. Then loop over it.

Pattern 6: Looping with break and continue
Sometimes you need to stop the loop early (break) or skip an iteration (continue).

Python

# break: stop when condition is met

for num in range(1, 100):

if num ** 2 > 50:

break

print(f”{num}^2 = {num**2}”)

# Stops at 8^2 = 64 (first square to exceed 50 is 7^2=49, 8^2=64)

# continue: skip current iteration

for num in range(1, 11):

if num % 2 == 0:

continue

print(num, end=” “)

# 1 3 5 7 9 (skips even numbers)

Pattern 7: Loop with else (Search Pattern)
The else clause runs only if the loop completes without a break. Perfect for search loops.

Python

# Find a prime number

num = 17

for i in range(2, int(num ** 0.5) + 1):

if num % i == 0:

print(f”{num} is not prime (divisible by {i})”)

break

else:

print(f”{num} is prime”)

# Output: 17 is prime

# Search in a list

colors = [“red”, “green”, “blue”, “yellow”]

target = “purple”

for color in colors:

if color == target:

print(f”Found {target}”)

break

else:

print(f”{target} not found”)

# Output: purple not found

⚠️ The else in a loop is counterintuitive. It runs when there is no break. Document it clearly when you use it.
Pattern 8: Looping Through Dictionaries with .items()
Always use .items() to get key-value pairs. Do not loop through keys and then look up values.

Python

person = {“name”: “Feloriya”, “age”: 25, “city”: “Tehran”}

# Bad way (looks up value each time)

for key in person:

print(f”{key}: {person[key]}”)

# Good way (direct unpacking)

for key, value in person.items():

print(f”{key}: {value}”)

Pattern 9: Nested Loop Unpacking
When looping through nested structures, you can unpack directly in the loop header.

Python

# List of tuples

points = [(1, 2), (3, 4), (5, 6)]

for x, y in points:

print(f”x: {x}, y: {y}”)

# List of lists

coordinates = [[10, 20], [30, 40], [50, 60]]

for x, y in coordinates:

print(f”x: {x}, y: {y}”)

🕯️ Magic Note

Unpacking works in loops just like it works in assignments. Python automatically assigns each element of the inner sequence to the corresponding variable.

Pattern 10: Skipping First or Last Items
Use slicing to skip items at the beginning or end of a sequence when looping.

Python

items = [10, 20, 30, 40, 50]

# Skip first item

for item in items[1:]:

print(item, end=” “)

# 20 30 40 50

# Skip last item

for item in items[:-1]:

print(item, end=” “)

# 10 20 30 40

# Skip first and last

for item in items[1:-1]:

print(item, end=” “)

# 20 30 40

💡 Slicing creates a new list. For very large lists, use itertools.islice() which does not create a copy.
Pattern 11: Pairwise Iteration (Adjacent Pairs)
Loop through adjacent pairs of items. Useful for comparing consecutive elements.

Python

numbers = [1, 3, 5, 7, 9]

# Manual way

for i in range(len(numbers) – 1):

print(f”{numbers[i]} -> {numbers[i+1]}”)

# Using zip (more Pythonic)

for a, b in zip(numbers, numbers[1:]):

print(f”{a} -> {b}”)

# 1 -> 3

# 3 -> 5

# 5 -> 7

# 7 -> 9

Pattern 12: Using itertools for Advanced Loops
The itertools module provides powerful tools for complex iteration patterns.

Python

from itertools import cycle, combinations, product

# cycle: repeat endlessly

colors = [“red”, “green”, “blue”]

for color in cycle(colors):

print(color)

# red, green, blue, red, green, blue … (infinite)

# combinations: all unique pairs

names = [“Ali”, “Sara”, “Reza”]

for a, b in combinations(names, 2):

print(f”{a} – {b}”)

# Ali – Sara

# Ali – Reza

# Sara – Reza

# product: Cartesian product

suits = [“hearts”, “diamonds”]

values = [“A”, “K”]

for suit, value in product(suits, values):

print(f”{value} of {suit}”)

# A of hearts, K of hearts, A of diamonds, K of diamonds

Common Mistakes with Loop Patterns
  • Using range(len(list)) instead of enumerate()
  • Modifying a list while iterating over it (use a copy or collect changes)
  • Forgetting that zip() stops at the shortest iterable
  • Using reversed() on a set (sets have no order)
  • Confusing sorted() (returns new list) with .sort() (modifies in place)
  • Using else with a loop without understanding its behavior
Check Your Understanding
  • How do you loop through a list with both index and value?
  • Write code that loops through two lists names and scores together.
  • How do you loop through a list in reverse order without modifying it?
  • What is the difference between sorted() and .sort() in loops?
  • Write a loop that finds if a number exists in a list and uses else to handle “not found”.
  • How do you loop through adjacent pairs like [(1,2), (2,3), (3,4)]?

⚡ Whisper

The simple for loop is a seed. These patterns are the flowers that grow from it. enumerate() gives you position without counting. zip() weaves lists together like threads in a tapestry. reversed() walks backwards through time. sorted() brings order from chaos. Each pattern is a tool in your belt. You do not need to memorize them all at once. Learn one. Use it until it becomes natural. Then learn another. Soon you will see iteration problems and the pattern will appear in your mind like a whisper. That is mastery. Not knowing every tool. Knowing which tool fits the moment.

Related posts