Lambdas, map, filter & reduce
In short: a lambda is a one-expression, unnamed function —
lambda x: x * 2 is a value, exactly like def double(x): return x * 2 is,
just with no name and no return keyword (the expression's result is
returned automatically). map(fn, items) runs fn on every item. filter(fn, items) keeps only the items where fn returns truthy. Both return lazy
iterators, not lists — wrap them in list(...) to see or reuse the
results. functools.reduce(fn, items, start) folds a whole sequence down to
one value, two items at a time. Reach for a lambda only when the whole
function is one expression; anything with a name, a loop, or more than one
line reads better as a def.

Sort orders by price
A café app lists today's orders, cheapest first. sorted() takes a key
function it calls once per item — a perfect one-line job for a lambda:
key=lambda o: o["price"] just names which field to compare — it never runs
on its own, only when sorted calls it. Writing a whole def by_price(o): return o["price"] above the call would work identically, but for a
one-line rule read right where it's used, the lambda is clearer.
A lambda can only hold one expression — no = assignment, no for, no
if statement (a ternary a if cond else b is fine, because that's an
expression too):
mark_cheap = lambda price: cheap = price < 50
print(mark_cheap(30))Double every price with map
The café wants a festival menu at double the price. map() applies one
function across a whole list and hands back an iterator:
prices = [20, 60, 90]
doubled = map(lambda p: p * 2, prices)
print(doubled[0])That laziness has a second trap: a map (or filter) object is used up the moment you read it once.
Run it: the second line prints 0, not 3. Store the list once and read it twice.
Filter out cancelled orders, then total the rest
filter() keeps only the items a function approves of. Chain it with map()
and functools.reduce() and you can read a whole pipeline left to right —
keep the active ones, pull out their prices, fold them into one total:
reduce calls its lambda on the running total and the next price, over and
over, until one number is left: 0+20=20, then 20+30=50. The starting
value (0 here) also protects against an empty list — without it, reduce
on an empty sequence raises TypeError.
Once the "keep, then combine" logic needs more than one line — say, also
logging each cancelled order's name — a plain for loop or a named def
reads better than three chained lambdas. Lambdas earn their place when they
stay this short.
Quick practice
nums = [1, 2, 3, 4, 5]
evens = filter(lambda n: n % 2 == 0, nums)
print(list(evens), list(evens))from functools import reduce
words = ["ok"]
print(reduce(lambda a, b: a + " " + b, words))NameErrorFix the sort so it runs, ordering names by length.
prices = []
from functools import reduce
print(reduce(lambda a, b: a + b, prices))🎯 Your turn
Write active_total(orders). Each order is a dict with "price" and
"cancelled". Filter out the cancelled ones, map each remaining
order to its price, then reduce those prices to one total (start at 0).
active_total([{"price": 20, "cancelled": False}, {"price": 15, "cancelled": True}])→20active_total([])→0
Hint: filter(lambda o: not o["cancelled"], orders), then
map(lambda o: o["price"], ...), then functools.reduce(lambda a, b: a + b, ..., 0).
Press ▶ Run, try the Live App chips, then ✓ Check. After that, the practice set below goes from one lambda to a full filter-map-reduce pipeline.
