C.W.K.
Stream
Lesson 06 of 07 · published

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))        # []

External links

Exercise

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.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.