Lambda, map and filter
In Python, functions are values, just like numbers and strings. You can store them in variables, put them in lists and pass them to other functions. This lesson shows how, and introduces lambda, a quick way to write tiny functions on the spot.
Functions are values
A function name without () refers to the function itself, without calling it:
def shout(text):
return text.upper() + "!"
yell = shout # no parentheses: we're not calling it
print(yell("hello"))
print(type(shout))So you can pass a function into another function:
def apply_twice(func, value):
return func(func(value))
def add_three(n):
return n + 3
print(apply_twice(add_three, 10))Lambda functions
A lambda is a small function written in a single expression, without def or a name:
lambda parameters: expression
These two do the same thing:
def square(n):
return n * n
square_lambda = lambda n: n * n
print(square(6))
print(square_lambda(6))A lambda can take several parameters, and its expression is returned automatically:
add = lambda a, b: a + b
full_name = lambda first, last: f"{first} {last}".title()
print(add(2, 3))
print(full_name("ada", "lovelace"))Lambdas are limited to one expression: no loops, no assignments, no multiple statements. Their real use is as short throwaway functions passed to other functions.
Sorting with a key
sorted(), min() and max() accept a key function. It's called on each item, and the results decide the order. This is where lambdas are used most:
words = ["banana", "Apple", "cherry", "date"] print(sorted(words)) # capitals first print(sorted(words, key=str.lower)) # case-insensitive print(sorted(words, key=len)) # by length print(sorted(words, key=lambda w: w[-1])) # by last letter
It's especially handy for lists of tuples or dictionaries:
students = [("Mia", 88), ("Leo", 95), ("Ava", 72)]
by_score = sorted(students, key=lambda s: s[1], reverse=True)
print(by_score)
best = max(students, key=lambda s: s[1])
print("Top student:", best[0])products = [
{"name": "Laptop", "price": 999},
{"name": "Mouse", "price": 25},
{"name": "Monitor", "price": 249},
]
cheapest_first = sorted(products, key=lambda p: p["price"])
for p in cheapest_first:
print(p["name"], p["price"])map(): apply a function to every item
map(function, iterable) calls the function on each item. It returns a lazy map object, so wrap it in list() to see the results:
numbers = [1, 2, 3, 4] doubled = map(lambda n: n * 2, numbers) print(doubled) # a map object print(list(doubled)) print(list(map(str.upper, ["a", "b", "c"]))) print(list(map(int, ["10", "20", "30"]))) # convert strings to ints
A common trick reads several numbers from one line of input:
line = "3 8 15 4" numbers = list(map(int, line.split())) print(numbers, sum(numbers))
filter(): keep the items that pass a test
filter(function, iterable) keeps the items for which the function returns something truthy:
numbers = [5, 12, 7, 20, 3, 18] big = filter(lambda n: n > 10, numbers) print(list(big)) words = ["", "hello", "", "world"] print(list(filter(None, words))) # None keeps only truthy items
Comprehensions are often clearer
Anything map and filter do, a list comprehension can do too, and many Python programmers find the comprehension easier to read:
numbers = [5, 12, 7, 20, 3, 18] print(list(map(lambda n: n * 2, numbers))) print([n * 2 for n in numbers]) print(list(filter(lambda n: n > 10, numbers))) print([n for n in numbers if n > 10])
A good rule of thumb:
- Use
mapwhen you already have a named function:map(int, parts). - Use a comprehension when you'd need a lambda.
- Use a lambda mostly for
key=arguments.
Going deeper: any() and all() optional
Two more built-ins answer yes-or-no questions about a whole collection:
any(items)isTrueif at least one item is truthy.all(items)isTrueif every item is truthy.
They pair nicely with a comprehension that turns each item into True or False:
scores = [72, 85, 90, 66] print(any(s >= 90 for s in scores)) # did anyone get 90 or more? print(all(s >= 50 for s in scores)) # did everyone pass? print(all(s >= 70 for s in scores))
Notice there are no square brackets inside any() and all(). That's a generator expression, which you'll meet in Iterators and Generators. Writing any([s >= 90 for s in scores]) with brackets works too.
Both stop as soon as they know the answer, so any() stops at the first True. On an empty collection, any([]) is False and all([]) is True, because no item breaks the rule.
Exercises
Exercise 1: Sort by length
Sort the names from shortest to longest using sorted() with a key. It should print ['Al', 'Mia', 'Grace', 'Alexander'].
names = ["Grace", "Al", "Alexander", "Mia"]
sorted() takes a key function that decides the order.
The built-in len already gives each name's length: sorted(names, key=len).
Exercise 2: Most expensive item
Use max() with a lambda to find the most expensive item, and print its name: Laptop.
items = [("Pen", 1.5), ("Laptop", 899.0), ("Book", 12.99)]
Each item is a tuple (name, price), so the price is item[1].
Use max(items, key=lambda item: item[1]), then print the first part of the result.
Exercise 3: map and filter
Use filter to keep the odd numbers, then map to square them, and print the list: [1, 9, 25, 49, 81].
numbers = list(range(1, 11))
filter(lambda n: n % 2 == 1, numbers) keeps the odd numbers.
Pass that into map(lambda n: n ** 2, ...) and wrap the result in list().
Exercise 4: Rewrite as a comprehension
Rewrite the map/filter line as a single list comprehension that gives the same result.
words = ["python", "is", "fun", "and", "powerful"] result = list(map(str.upper, filter(lambda w: len(w) > 3, words))) print(result)
map(str.upper, ...) becomes w.upper() at the front of the comprehension.
The filter condition becomes if len(w) > 3 at the end.
Functions that take functions at a glance
A quick reference for later. The examples use words = ["kiwi", "fig", "banana"] and nums = [3, -5, 2].
| Tool | What it does | Example | Result |
|---|---|---|---|
lambda args: expr |
A small one-line function | (lambda x: x * 2)(5) |
10 |
sorted(items, key=f) |
Sorts by f(item) instead of the item itself |
sorted(words, key=len) |
['fig', 'kiwi', 'banana'] |
sorted(items, key=f, reverse=True) |
The same, largest first | sorted(words, key=len, reverse=True) |
['banana', 'kiwi', 'fig'] |
items.sort(key=f) |
Like sorted(), but sorts the list in place |
words.sort(key=len) |
words becomes ['fig', 'kiwi', 'banana'] |
min(items, key=f) |
The item with the smallest f(item) |
min(nums, key=abs) |
2 |
max(items, key=f) |
The item with the largest f(item) |
max(words, key=len) |
'banana' |
map(f, items) |
Applies f to every item |
list(map(abs, nums)) |
[3, 5, 2] |
filter(f, items) |
Keeps the items where f(item) is truthy |
list(filter(lambda n: n > 0, nums)) |
[3, 2] |
filter(None, items) |
Keeps only the truthy items | list(filter(None, [0, 1, "", "a"])) |
[1, 'a'] |
any(...) |
Is at least one item truthy? | any(n < 0 for n in nums) |
True |
all(...) |
Is every item truthy? | all(n < 0 for n in nums) |
False |
Summary
- Functions are values: you can store them and pass them to other functions.
lambda params: expressionmakes a small one-expression function.sorted,minandmaxtake akey=function that decides the order.map(func, items)transforms every item, andfilter(func, items)keeps the items that pass.- Wrap
mapandfilterinlist()to see the results. - When you'd need a lambda, a list comprehension is often clearer.