List Comprehensions

Difficulty: Beginner

Question

Explain list comprehensions in Python. How do they compare to loops?

Answer

List comprehensions provide a concise way to create lists based on existing iterables. They are generally faster than equivalent for-loop constructions because they are optimized at the C level in CPython.

Syntax: [expression for item in iterable if condition]

Types of comprehensions: - List: [x for x in range(10)] - Dict: {k: v for k, v in items} - Set: {x for x in range(10)} - Generator expression: (x for x in range(10)) - lazy evaluation

Comprehensions should be readable. If they get too complex (multiple conditions, deep nesting), use a regular loop instead.

Code examples

Basic List Comprehensions

# Simple transformation
squares = [x  2 for x in range(10)]
print(squares)  # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

# With filtering
evens = [x for x in range(20) if x % 2 == 0]
print(evens)  # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

# Conditional expression (ternary in comprehension)
labels = ['even' if x % 2 == 0 else 'odd' for x in range(5)]
print(labels)  # ['even', 'odd', 'even', 'odd', 'even']

# String processing
words = ['  Hello ', ' World  ', '  Python ']
cleaned = [w.strip().lower() for w in words]
print(cleaned)  # ['hello', 'world', 'python']

# Flattening with method calls
sentences = ['hello world', 'foo bar baz']
all_words = [word for sentence in sentences for word in sentence.split()]
print(all_words)  # ['hello', 'world', 'foo', 'bar', 'baz']

The if clause filters items. Ternary expressions (x if cond else y) transform each item. Nested for clauses flatten nested structures.

Dict, Set, and Nested Comprehensions

# Dict comprehension
word_lengths = {word: len(word) for word in ['hello', 'world', 'python']}
print(word_lengths)  # {'hello': 5, 'world': 5, 'python': 6}

# Set comprehension (auto-deduplicates)
first_letters = {word[0] for word in ['apple', 'avocado', 'banana', 'blueberry']}
print(first_letters)  # {'a', 'b'}

# Nested comprehension: 2D matrix
matrix = [[i * j for j in range(1, 4)] for i in range(1, 4)]
print(matrix)  # [[1, 2, 3], [2, 4, 6], [3, 6, 9]]

# Flatten a matrix
flat = [val for row in matrix for val in row]
print(flat)  # [1, 2, 3, 2, 4, 6, 3, 6, 9]

# Transpose a matrix
transposed = [[row[i] for row in matrix] for i in range(3)]
print(transposed)  # [[1, 2, 3], [2, 4, 6], [3, 6, 9]]

Comprehensions work for dicts and sets too. Nested comprehensions read left-to-right matching nested for-loop order.

Performance: Comprehension vs Loop

import time

# Loop approach
start = time.time()
result = []
for i in range(1_000_000):
    result.append(i  2)
loop_time = time.time() - start

# Comprehension approach
start = time.time()
result = [i  2 for i in range(1_000_000)]
comp_time = time.time() - start

print(f"Loop: {loop_time:.4f}s")
print(f"Comprehension: {comp_time:.4f}s")
print(f"Speedup: {loop_time / comp_time:.1f}x")

# When NOT to use comprehension
# Bad: too complex, hard to read
# result = [transform(x) for x in data if validate(x) for y in x.items() if check(y)]

# Better: use a regular loop
result = []
for x in data:
    if validate(x):
        for y in x.items():
            if check(y):
                result.append(transform(x))

Comprehensions are faster because they avoid the overhead of list.append() method lookup on each iteration. But readability matters more than micro-optimization.

Key points

Concepts covered

List Comprehension, Dict Comprehension, Set Comprehension, Nested Comprehension, Filtering