Iteration Helpers — map, filter, and Why You Probably Won't Use Them
~15 min · map, filter, functional, comprehension
Level 0Curious
0 XP0/93 lessons0/23 achievements
0/100 XP to next level100 XP to go0% complete
The functional pair you'll see in old code
map(fn, iterable) applies fn to each element. filter(pred, iterable) keeps elements where pred(x) is truthy. They've been in Python forever; they exist in most languages. They're also not the most Pythonic way to do these operations anymore. Comprehensions almost always read better.
Why comprehensions usually win
[x*2 for x in nums] is shorter and clearer than list(map(lambda x: x*2, nums)). [x for x in nums if x > 0] beats list(filter(lambda x: x > 0, nums)). The comprehension keeps the expression at the front and the predicate at the back; you read the result first. That readability bias is most of why comprehensions won.
When map and filter still earn their keep
Two cases: when the function you're mapping is already named (like a method), map(str.upper, words) can be cleaner than [w.upper() for w in words]. And when you want a lazy iterator (no list materialized), map and filter return iterators in Python 3 — the same lazy nature as a generator expression.
any, all — the underrated reducers
Two iteration helpers that are idiomatic: any(iterable) returns True if any element is truthy. all(iterable) returns True if every element is truthy. Both short-circuit. Combined with a generator expression, they read beautifully: if any(x < 0 for x in nums).
Pythonic Way: When you reach for map or filter, ask whether a comprehension would be clearer. The answer is yes >90% of the time. The remaining cases are real, but they're the exception.
Code
map vs comprehension·python
nums = [1, 2, 3, 4, 5]
# functional style
result = list(map(lambda x: x * 2, nums))
print(result) # [2, 4, 6, 8, 10]
# comprehension — usually clearer
result = [x * 2 for x in nums]
print(result) # [2, 4, 6, 8, 10]
# When map IS clearer — when the function is already named
words = ["alpha", "beta", "gamma"]
upper = list(map(str.upper, words)) # arguably nicer
upper = [w.upper() for w in words] # also fine
filter vs comprehension with if·python
nums = [-2, -1, 0, 1, 2]
# functional
positives = list(filter(lambda x: x > 0, nums))
print(positives) # [1, 2]
# comprehension
positives = [x for x in nums if x > 0]
print(positives) # [1, 2]
# Combined — comprehension keeps it on one line
result = [x * 10 for x in nums if x > 0]
print(result) # [10, 20]
any and all — reducers that read like English·python
nums = [1, 2, 3, 4, 5]
# Are any negative?
print(any(x < 0 for x in nums)) # False
# Are all positive?
print(all(x > 0 for x in nums)) # True
# Both short-circuit — they stop at the first decisive element
def expensive(x):
print("checking", x)
return x > 100
any(expensive(x) for x in [50, 150, 200])
# checking 50
# checking 150 <- returns True here, doesn't check 200
map returns a lazy iterator in Python 3·python
result = map(str.upper, ["a", "b", "c"])
print(result) # <map object at 0x...>
print(list(result)) # ['A', 'B', 'C']
# After consumed, the iterator is empty
print(list(result)) # []
Given nums = [-3, -1, 0, 4, 7, 12]: (a) Use map and filter ONLY (no comprehensions, no for-loops) to produce a list of squares of the positive numbers. (b) Then rewrite (a) as a single comprehension. (c) Use any to check if any number is greater than 10, and all to check if all are greater than -5. Print all four results.
Progress
Progress is local-only — sign in to sync across devices.