Skip to content

Comprehensions & Generator Expressions

One syntax for all collection transformations

Section titled “One syntax for all collection transformations”

TypeScript developers reach for .map(), .filter(), and .reduce() chained on arrays. This works, but it requires creating intermediate arrays at each step and cannot natively produce a Set or an object directly. Python has comprehension syntax built into the language for four forms: list, dict, set, and generator. The mental model is: [expression for item in iterable if condition].

The most common case is transforming a collection while optionally filtering it. In TypeScript this is two separate method calls. In Python it is a single expression.

TypeScript
// TypeScript: chained .map() and .filter()
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// squares of even numbers
const result = numbers
.filter(n => n % 2 === 0)
.map(n => n ** 2);
console.log(result); // [4, 16, 36, 64, 100]
// Building an object from an array requires reduce or Object.fromEntries
const words = ["hello", "world", "typescript"];
const wordLengths = Object.fromEntries(
words.map(w => [w, w.length])
);
console.log(wordLengths); // { hello: 5, world: 5, typescript: 10 }
Python
# Python: comprehensions for list, dict, set, and generator
numbers = list(range(1, 11))
# squares of even numbers — single expression
result = [n ** 2 for n in numbers if n % 2 == 0]
print(result) # [4, 16, 36, 64, 100]
# Dict comprehension — no need for Object.fromEntries
words = ["hello", "world", "python"]
word_lengths = {word: len(word) for word in words}
print(word_lengths) # {'hello': 5, 'world': 5, 'python': 6}
# Set comprehension — duplicates are automatically removed
unique_lengths = {len(word) for word in words}
print(unique_lengths) # {5, 6}

List comprehension — produces an eager list:

squares = [x ** 2 for x in range(1, 6)]
# [1, 4, 9, 16, 25]

Dict comprehension — produces a dict:

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

Set comprehension — produces a set (no duplicate values):

unique_lengths = {len(word) for word in ["hi", "hello", "hey", "world"]}
# {2, 3, 5}

Generator expression — produces a lazy generator (parentheses, not brackets):

gen = (x ** 2 for x in range(5))
# Nothing is computed yet. Values are produced only when iterated.
print(list(gen)) # [0, 1, 4, 9, 16]

The syntax is identical across all four forms; only the outer delimiter changes: [] for list, {} with a colon for dict, {} without a colon for set, and () for generator.

# List comprehension
squares = [x ** 2 for x in range(1, 6)]
print(squares)
# With filter condition
evens = [x for x in range(10) if x % 2 == 0]
print(evens)
# Dict comprehension
word_lengths = {word: len(word) for word in ["hello", "world", "python"]}
print(word_lengths)
# Set comprehension -- unique values only
unique_lengths = {len(word) for word in ["hi", "hello", "hey", "world"]}
print(sorted(unique_lengths))
# Generator expression -- lazy
gen = (x ** 2 for x in range(5))
print(list(gen))
Which syntax produces a Python set comprehension?
What is the key difference between a list comprehension and a generator expression?
What happens if you iterate a generator expression twice?
Which of the following is the most memory-efficient way to sum the squares of numbers 0 through 999?