No history yet

Efficient Iteration Patterns

A Better Way to Loop

You're likely familiar with using for loops to build new lists. The pattern is common: initialize an empty list, loop over another sequence, and append a new element on each pass. It works, but it's not the most efficient or readable way to get the job done in Python.

Python offers a more concise and elegant syntax called a list comprehension. It lets you create a new list based on an existing iterable in a single, readable line. Let's transform a standard loop into a comprehension.

# The old way with a for loop
squares = []
for i in range(5):
    squares.append(i * i)

# The Pythonic way with a list comprehension
squares_comp = [i * i for i in range(5)]

print(squares_comp)
# Output: [0, 1, 4, 9, 16]

The comprehension reads almost like plain English: "make a new list with i * i for each i in the range of 5." This approach is not only shorter but often faster because the iteration happens at a lower level in Python's implementation.

Conditional Logic

Comprehensions get even more powerful when you add conditional logic. You can filter elements from the original iterable, so only items that meet a certain condition are included in the new list. To do this, you add an if statement at the end of the comprehension.

# Get the squares of even numbers only
even_squares = [i * i for i in range(10) if i % 2 == 0]

print(even_squares)
# Output: [0, 4, 16, 36, 64]

This filters the numbers from 0 to 9, processing only the even ones. You can also use a conditional expression (like an if-else statement) to change the output for each element, but the syntax is a bit different. The if-else comes before the for loop.

# Label numbers as 'even' or 'odd'
labels = ['even' if i % 2 == 0 else 'odd' for i in range(5)]

print(labels)
# Output: ['even', 'odd', 'even', 'odd', 'even']

Comprehensions for Sets and Dictionaries

This powerful syntax isn't limited to lists. You can create sets and dictionaries using a very similar pattern. A set comprehension uses curly braces {} and ensures the final collection only contains unique elements.

# Create a set of unique letters from a string
word = 'mississippi'
unique_letters = {letter for letter in word}

print(unique_letters)
# Output: {'i', 'p', 's', 'm'}

A dictionary comprehension also uses curly braces but requires a key-value pair, separated by a colon, as its expression. This is incredibly useful for creating dictionaries on the fly.

# Create a dictionary mapping numbers to their squares
square_map = {i: i * i for i in range(5)}

print(square_map)
# Output: {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

Handling Multiple Sequences

What if you need to loop over two or more lists at the same time? For example, matching a list of names with a list of ages. Python's built-in zip() function is designed for exactly this. It takes multiple iterables and aggregates them into a single iterator of tuples.

Each tuple contains the elements at the same index from each of the original iterables. The iteration stops as soon as the shortest iterable is exhausted.

names = ['Alice', 'Bob', 'Charlie']
ages = [25, 30, 35]

for name, age in zip(names, ages):
    print(f'{name} is {age} years old.')

# Output:
# Alice is 25 years old.
# Bob is 30 years old.
# Charlie is 35 years old.

Naturally, you can combine zip() with comprehensions to create powerful and concise data transformations.

names = ['Alice', 'Bob', 'Charlie']
ages = [25, 30, 35]

# Create a dictionary from two lists
user_data = {name: age for name, age in zip(names, ages)}

print(user_data)
# Output: {'Alice': 25, 'Bob': 30, 'Charlie': 35}

Tracking the Index

Another common need is to access the index of an item while iterating. The traditional C-style approach is to create a counter variable and increment it inside the loop. But Python provides a much cleaner solution: the enumerate() function.

enumerate() wraps an iterable and, on each pass, yields both the index and the item as a tuple. This avoids manual index management and makes the code more readable.

items = ['apple', 'banana', 'cherry']

# Without enumerate
index = 0
for item in items:
    print(f'Index {index}: {item}')
    index += 1

# With enumerate
for index, item in enumerate(items):
    print(f'Index {index}: {item}')

Just like zip(), enumerate() works beautifully inside comprehensions. It's perfect for when you need to create data structures that map an index to a value.

items = ['apple', 'banana', 'cherry']

# Create a dictionary mapping index to item
item_map = {index: item for index, item in enumerate(items)}

print(item_map)
# Output: {0: 'apple', 1: 'banana', 2: 'cherry'}

By mastering comprehensions, zip(), and enumerate(), you can write more efficient, readable, and Pythonic code for your data processing tasks.

Ready to test your knowledge?

Quiz Questions 1/6

Which of the following is the correct list comprehension equivalent for this for loop?

squares = []
for i in range(5):
  squares.append(i * i)
Quiz Questions 2/6

What is the output of the following code snippet?

numbers = [x for x in range(10) if x % 2 == 0]
print(numbers)

These patterns are fundamental to writing clean and effective Python. Practising them will make your code more robust and easier for others to understand.