No history yet

Advanced Collection Logic

A More Pythonic Way to Loop

You're already familiar with using for loops to iterate over a list and build a new one. It's a fundamental pattern in programming. For example, to get a list of squared numbers, you might write:

numbers = [1, 2, 3, 4, 5]
squares = []
for n in numbers:
    squares.append(n * n)

# squares is now [1, 4, 9, 16, 25]

This works perfectly, but it's a bit verbose for such a common task. Python offers a more concise and expressive way to do the same thing: a list comprehension. It's a single line of code that reads almost like plain English: "make a new list of n*n for each n in numbers."

numbers = [1, 2, 3, 4, 5]
squares = [n * n for n in numbers]

# squares is also [1, 4, 9, 16, 25]

This is considered more because it's clean, readable, and directly states the intent—creating a new list based on an existing one. Comprehensions are often faster than the equivalent for loop with append calls, as the process is optimized behind the scenes.

Adding Logic with Conditionals

Comprehensions become even more powerful when you add conditional logic. You can filter items from the original list by adding an if statement at the end.

Let's say we only want the squares of the even numbers from our list.

numbers = [1, 2, 3, 4, 5]
even_squares = [n * n for n in numbers if n % 2 == 0]

# even_squares is [4, 16]

The if n % 2 == 0 part acts as a filter. Only the items that pass this test are included in the new list. What if you want to transform items differently based on a condition, rather than just filtering them out? You can use a conditional expression (often called a ternary operator) at the beginning of the comprehension.

numbers = [1, 2, 3, 4, 5]
labels = ['even' if n % 2 == 0 else 'odd' for n in numbers]

# labels is ['odd', 'even', 'odd', 'even', 'odd']

Notice the placement. A filtering if goes at the end. A transforming if-else goes at the beginning. This syntax clearly separates the two different kinds of logic.

Beyond Lists

This concise syntax isn't limited to lists. You can also create dictionaries and sets in a similar way. This is incredibly useful for restructuring data.

Dictionary Comprehensions A dictionary comprehension uses curly braces {} and a key: value pair in the expression. Let's create a dictionary mapping each number to its square.

numbers = [1, 2, 3, 4, 5]
squares_dict = {n: n*n for n in numbers}

# squares_dict is {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

This is a fast way to build lookup tables. For instance, you could take a list of user objects and create a dictionary that maps user IDs to their email addresses for quick access.

Set Comprehensions Set comprehensions also use curly braces but don't have a key: value pair. They are perfect for creating a collection of unique items.

words = ['hello', 'world', 'hello', 'python', 'world']
unique_words = {word for word in words}

# unique_words is {'hello', 'world', 'python'}

Handling Nested Data

Sometimes you need to work with lists inside of other lists. Comprehensions can handle this, too, by using nested for loops. The most common use case is flattening a list of lists into a single list.

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

flat_list = [num for row in matrix for num in row]

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

The order of the for loops in the comprehension matches the order they would appear in a standard nested loop. The for row in matrix is the outer loop, and for num in row is the inner loop.

While powerful, nested comprehensions can quickly become hard to read. If your logic involves more than two for loops or complex conditions, a standard set of nested loops is often the more readable and maintainable choice.

Quiz Questions 1/6

What is the primary advantage of using a list comprehension like [n*n for n in numbers] over a traditional for loop with .append()?

Quiz Questions 2/6

Which code snippet correctly creates a new list containing only the numbers greater than 10 from a list called nums?