map() and filter()¶
map() applies a function to every element of an iterable. filter() keeps only the elements for which a function returns True. Both return lazy iterators — wrap with list() to materialise the result.
map()¶
def square(x: int) -> int:
return x ** 2
numbers = [1, 2, 3, 4, 5]
squared = list(map(square, numbers))
print(squared) # [1, 4, 9, 16, 25]
With a lambda instead of a named function:
squared = list(map(lambda x: x ** 2, numbers))
print(squared) # [1, 4, 9, 16, 25]
map() can take multiple iterables — the function receives one element from each:
a = [1, 2, 3]
b = [10, 20, 30]
sums = list(map(lambda x, y: x + y, a, b))
print(sums) # [11, 22, 33]
Passing a named method works too:
words = ["hello", "world", "python"]
upper = list(map(str.upper, words))
print(upper) # ['HELLO', 'WORLD', 'PYTHON']
filter()¶
def is_even(x: int) -> bool:
return x % 2 == 0
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
evens = list(filter(is_even, numbers))
print(evens) # [2, 4, 6, 8, 10]
With a lambda:
evens = list(filter(lambda x: x % 2 == 0, numbers))
Filtering strings:
words = ["apple", "banana", "apricot", "cherry", "avocado"]
a_words = list(filter(lambda w: w.startswith("a"), words))
print(a_words) # ['apple', 'apricot', 'avocado']
Passing None as the function keeps all truthy values:
values = [0, 1, False, True, "", "hello", None, [], [1, 2]]
truthy = list(filter(None, values))
print(truthy) # [1, True, 'hello', [1, 2]]
Combining map() and filter()¶
Chain them by passing one as the input to the other:
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# Squares of even numbers only
result = list(map(lambda x: x ** 2, filter(lambda x: x % 2 == 0, numbers)))
print(result) # [4, 16, 36, 64, 100]
map() and filter() vs List Comprehensions¶
Both approaches produce identical results. Choose based on readability:
numbers = [1, 2, 3, 4, 5]
# Transform
list(map(lambda x: x ** 2, numbers)) # map
[x ** 2 for x in numbers] # comprehension
# Filter
list(filter(lambda x: x % 2 == 0, numbers)) # filter
[x for x in numbers if x % 2 == 0] # comprehension
# Combined
list(map(lambda x: x**2, filter(lambda x: x % 2 == 0, numbers))) # map + filter
[x**2 for x in numbers if x % 2 == 0] # comprehension
List comprehensions are generally preferred in modern Python — they read left to right and require no lambda. Reach for map() or filter() when you already have a named function to pass:
words = [" alice ", "BOB", " Charlie"]
cleaned = list(map(str.strip, words)) # cleaner than a lambda here
Practical Examples¶
Clean and format names:
names = [" alice ", "BOB", " Charlie"]
cleaned = list(map(lambda s: s.strip().title(), names))
print(cleaned) # ['Alice', 'Bob', 'Charlie']
Temperature conversion:
celsius = [0, 10, 20, 30, 100]
fahrenheit = list(map(lambda c: c * 9 / 5 + 32, celsius))
print(fahrenheit) # [32.0, 50.0, 68.0, 86.0, 212.0]
Filter passing grades:
grades = [45, 78, 92, 55, 67, 88, 34, 91]
passing = list(filter(lambda g: g >= 60, grades))
print(passing) # [78, 92, 67, 88, 91]
print(f"Pass rate: {len(passing)/len(grades)*100:.1f}%") # 62.5%
Validate email addresses:
emails = ["user@example.com", "invalid", "test@test.org", "no-at-sign"]
valid = list(filter(lambda e: "@" in e and "." in e, emails))
print(valid) # ['user@example.com', 'test@test.org']
Key Ideas¶
map() transforms every element; filter() selects elements. Both are lazy — they produce one result at a time without building the full list in memory. List comprehensions are usually clearer for simple cases; map() and filter() shine when a named function is already available to pass directly.
We return to map() and filter() as functional programming tools — alongside reduce() and function composition — in map(), filter(), reduce().