Skip to content

Python · Functional Programming

Python map, filter & reduce Explained — Functional Transforms vs Comprehensions

4 min read Updated 2026-06-19 Share:

Practice map, filter & reduce interview questions

Python map, filter & reduce, explained

map, filter, and reduce are the classic functional trio for transforming, selecting, and folding sequences. Python supports all three, but it also has comprehensions — so the real interview question is usually when each is the right tool, not just how they work.

map — apply a function to every item

map(func, iterable) returns a lazy iterator that calls func on each element. Nothing runs until you consume it.

nums = [1, 2, 3, 4]
squared = map(lambda x: x * x, nums)   # a map object — nothing computed yet
list(squared)                          # [1, 4, 9, 16]

map can take multiple iterables, applying the function across them in parallel — handy and concise:

list(map(lambda a, b: a + b, [1, 2, 3], [10, 20, 30]))   # [11, 22, 33]

It stops at the shortest iterable. Because it's lazy, map over a huge sequence uses constant memory.

filter — keep items that pass a test

filter(predicate, iterable) yields only the elements for which predicate returns truthy. Passing None as the predicate keeps the truthy items.

nums = [0, 1, 2, 0, 3]
list(filter(lambda x: x > 1, nums))    # [2, 3]
list(filter(None, nums))               # [1, 2, 3] — drops falsy values

Like map, it returns a lazy iterator, so it composes cheaply into pipelines.

reduce — fold to a single value

reduce lives in functools (it was moved out of builtins in Python 3 because it's rarely the clearest option). It repeatedly applies a two-argument function, carrying an accumulator.

from functools import reduce

reduce(lambda acc, x: acc + x, [1, 2, 3, 4], 0)        # 10
reduce(lambda acc, x: acc * x, [1, 2, 3, 4], 1)        # 24

The optional initial value (last argument) is also the result for an empty iterable, which avoids a TypeError.

The Pythonic alternative: comprehensions

For map and filter, a list/generator comprehension is usually more readable — and it avoids a lambda entirely.

nums = [1, 2, 3, 4]

# map + filter
[x * x for x in nums if x % 2 == 0]            # [4, 16]

# vs the functional version
list(map(lambda x: x * x, filter(lambda x: x % 2 == 0, nums)))

The comprehension reads left-to-right and needs no lambda. Use a generator expression (x*x for x in nums) when you want laziness like map gives.

When map/filter still win

map is genuinely nicer when you already have a named function — no lambda, no rebuilding:

names = ["  alice ", "BOB  "]
list(map(str.strip, names))            # ['alice', 'BOB  '.strip()...] clean and direct
clean = [name.strip() for name in names]   # comprehension equivalent

map(int, tokens) or map(str.upper, words) are crisp. The moment you need a lambda, a comprehension is usually clearer.

reduce vs built-ins and loops

Most "reduce" tasks have a dedicated built-in: sum, min, max, any, all, "".join. Reach for those first — they're faster and clearer. Save reduce for genuine custom folds, and even then a plain for loop is often more readable to teammates.

# Don't:
reduce(lambda a, b: a + b, nums)
# Do:
sum(nums)

Recap

map applies a function to every item, filter keeps the ones passing a predicate, and both return lazy iterators; reduce (in functools) folds a sequence to one value with an accumulator and optional initial value. In modern Python, comprehensions and generator expressions usually replace map/filter more readably — but map(func, ...) with an existing named function stays elegant. For folds, prefer built-ins like sum, max, and join over reduce whenever one exists.

More ways to practice

The self-quiz is live. Get notified when mock interviews and new question packs drop.

or
Join our WhatsApp Channel