Previous | Tutorial index | Next
map, filter, and reduceHigher‑order functions are functions that operate on other functions—either by taking them as arguments or by returning them. Python provides several built‑in higher‑order functions that are extremely useful for processing iterables. The three most important ones are map, filter, and reduce. Together with lambda expressions, they enable a concise, functional programming style for data transformation, selection, and aggregation. In this tutorial, you’ll learn how to use these functions effectively, when they are appropriate, and how they compare to more Pythonic alternatives like comprehensions.
A higher‑order function is any function that:
Python functions are first‑class objects, so they can be passed around like any other value. This makes higher‑order functions natural in Python.
Examples you’ve already seen:
sorted(iterable, key=func) – key is a function.map(func, iterable) – func is applied to each element.filter(func, iterable) – func decides which elements to keep.map() Functionmap(function, iterable, ...) applies function to every element of the iterable(s) and returns an iterator that yields the results. The number of iterables passed must match the number of arguments expected by function.
map(func, iterable1, iterable2, ...)
# Square numbers
numbers = [1, 2, 3, 4]
squared = map(lambda x: x ** 2, numbers)
print(list(squared)) # [1, 4, 9, 16]
Important: map returns an iterator, not a list. You must convert it to a list (or iterate over it) to see the results. This is memory‑efficient for large data.
map with Multiple Iterablesa = [1, 2, 3]
b = [10, 20, 30]
sums = map(lambda x, y: x + y, a, b)
print(list(sums)) # [11, 22, 33]
The function receives one element from each iterable in parallel. If the iterables are of different lengths, map stops when the shortest is exhausted.
map vs. List ComprehensionList comprehensions are often more readable and Pythonic than map with a lambda:
# Using map
squared = list(map(lambda x: x**2, numbers))
# Using comprehension
squared = [x**2 for x in numbers]
For simple transformations, comprehensions are preferred. Use map when you already have a pre‑defined function and don't want to rewrite it inside a comprehension.
filter() Functionfilter(function, iterable) constructs an iterator from elements of the iterable for which function returns True. If function is None, it filters out falsy elements (like None, False, 0, empty strings, etc.).
filter(func, iterable)
numbers = [1, 2, 3, 4, 5, 6]
evens = filter(lambda x: x % 2 == 0, numbers)
print(list(evens)) # [2, 4, 6]
filter with Nonemixed = [0, 1, False, True, None, "hello", ""]
truthy = filter(None, mixed)
print(list(truthy)) # [1, True, "hello"]
filter vs. ComprehensionAgain, comprehensions are often clearer:
evens = [x for x in numbers if x % 2 == 0]
reduce() Function (from functools)reduce(function, iterable[, initializer]) applies function cumulatively to the items of iterable, reducing the iterable to a single value. It is not built‑in; it must be imported from functools.
from functools import reduce
reduce(func, iterable, initializer=None)
from functools import reduce
numbers = [1, 2, 3, 4]
product = reduce(lambda x, y: x * y, numbers)
print(product) # 24
The reduction proceeds as: (((1*2)*3)*4) = 24.
If you provide an initializer, it is placed before the iterable items in the reduction.
product = reduce(lambda x, y: x * y, numbers, 10)
print(product) # 240 (10 * 1 * 2 * 3 * 4)
If the iterable is empty, reduce returns the initializer; without an initializer, it raises TypeError.
reducesum() is built‑in for numbers).max() exists).reducereduce is less common than map and filter in modern Python because explicit loops or sum, any, all, etc., are often clearer. However, it shines in functional‑style pipelines.
Higher‑order functions can be chained to create data pipelines:
data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# Pipeline: square each, keep evens, sum
result = reduce(
lambda acc, x: acc + x,
filter(
lambda x: x % 2 == 0,
map(lambda x: x ** 2, data)
),
0
)
print(result) # 220 (4 + 16 + 36 + 64 + 100)
This is more readable if broken into steps:
squared = map(lambda x: x**2, data)
even_squared = filter(lambda x: x % 2 == 0, squared)
total = reduce(lambda a, b: a + b, even_squared, 0)
map and filter return iterators that evaluate lazily. This is efficient but can lead to confusion if you try to reuse them—they are exhausted after one pass.
m = map(lambda x: x*2, [1,2,3])
print(list(m)) # [2,4,6]
print(list(m)) # [] (iterator is exhausted)
If you need to reuse, convert to a list.
map and filterThese functions are meant for pure functions. Using them with functions that have side effects (like print) is considered bad practice. Use explicit loops instead.
If you already have a function defined, you can pass it directly:
def square(x): return x ** 2
squared = list(map(square, numbers))
List comprehensions and generator expressions are often more readable and faster than map/filter with lambdas:
[f(x) for x in iterable] instead of map(f, iterable)[x for x in iterable if pred(x)] instead of filter(pred, iterable)sum, any, all, max, min instead of reduce when possible.However, map and filter are still useful when you need to apply an existing function to multiple iterables (e.g., map(operator.add, a, b)) or when you’re working with functional patterns.
map with Multiple Iterables and zipmap can be used to combine values from multiple sequences:
list1 = [1, 2, 3]
list2 = [10, 20, 30]
list3 = [100, 200, 300]
sums = list(map(lambda a, b, c: a + b + c, list1, list2, list3)) # [111, 222, 333]
This is similar to using zip with a comprehension.
What does map return?
Which function from functools is used for cumulative reduction?
accumulatereducefoldaggregateGiven numbers = [1, 2, 3, 4], what is the result of list(filter(lambda x: x > 2, numbers))?
[3, 4][1, 2][2, 3, 4][1, 2, 3, 4]True or False: reduce is a built‑in function in Python and does not need to be imported.
What is the output of list(map(lambda x: x * 2, [1, 2, 3]))?
[2, 4, 6][1, 2, 3][1, 4, 9]NoneWhich of the following is more Pythonic for filtering even numbers?
filter(lambda x: x%2==0, numbers)[x for x in numbers if x%2==0]map(lambda x: x%2==0, numbers)If you call map with two iterables of different lengths, what happens?
ValueError.None.What does reduce(lambda x, y: x + y, [1, 2, 3], 10) return?
616107Which of the following is a higher‑order function?
len()sorted()print()type()What is the result of list(filter(None, [0, 1, False, 2, '']))?
[0, 1, 2][1, 2][0, 1, False, 2, ''][1, 2, '']Exercise 1: Map with Multiple Lists
Given list_a = [1, 2, 3] and list_b = [4, 5, 6], use map to compute element‑wise sums.
Exercise 2: Filter Strings
Given words = ["apple", "banana", "cherry", "date", "elderberry"], use filter to keep only words longer than 5 characters.
Exercise 3: Reduce Product
Use reduce to compute the product of all numbers in [2, 3, 4, 5].
Exercise 4: Chaining Pipelines
Write a pipeline that squares numbers 1–10, keeps those > 20, and sums them.
Exercise 5: Using map with Built‑in Functions
Use map with str.upper to convert a list of lowercase strings to uppercase.
1. Data Cleaning Pipeline
Given raw = [" 12 ", "34.5", " -7 ", "abc", " 0 "], write a pipeline that strips, converts to float (discarding invalid), and sums.
raw = [" 12 ", "34.5", " -7 ", "abc", " 0 "] valid = filter(lambda v: v is not None, map(to_float, raw)) total = sum(valid) print(total) # 39.5
</details>
**2. Custom `map` Implementation**
Write `my_map(func, *iterables)` that mimics `map` using `zip` and `yield`.
<details><summary>Sample Answer</summary>
```python
def my_map(func, *iterables):
for args in zip(*iterables):
yield func(*args)
print(list(my_map(lambda x, y: x + y, [1,2,3], [4,5,6]))) # [5,7,9]
3. Grouping and Aggregation with reduce
Use reduce to count numbers by tens digit (0–9).
4. Performance Comparison
Compare map vs list comprehension for squaring 10 million numbers using timeit.
5. Functional JSON Transformation
Given people, filter age ≥ 30, extract names, join with commas.
to_float(s) that returns float(s.strip()) or None. Then filter(lambda v: v is not None, map(to_float, raw)) and sum.zip(*iterables) and loop to yield func(*args).reduce(lambda acc, x: acc.update({x//10: acc.get(x//10,0)+1}) or acc, numbers, {}).timeit.timeit('list(map(lambda x: x**2, range(10000000)))', number=1) vs comprehension.filter(lambda p: p['age'] >= 30, people), then map(lambda p: p['name'], ...), then reduce(lambda acc, name: acc + (', ' if acc else '') + name, ..., '') or simply ', '.join(...).In this tutorial, you have learned:
map – applies a function to all elements of an iterable and returns an iterator.filter – selects elements that satisfy a predicate.reduce – cumulatively combines elements into a single value.These tools are valuable for writing expressive, functional‑style code. However, always prioritise readability and maintainability. In many cases, list comprehensions and generator expressions are clearer, but map and filter still have their niche, especially when you need to apply an existing function or work with multiple iterables.
Next Steps: In Tutorial 8, we will explore Decorators – a powerful way to modify or enhance functions without changing their source code.
Happy mapping, filtering, and reducing!