Python · Syntax · Intermediate

lambda, map, filter, reduce

10 tasks

Functional tools for transforming and filtering collections without writing explicit loops.

lambda syntax, map() and filter() return iterators, functools.reduce

#
**lambda — anonymous functions** A `lambda` is a single-expression anonymous function. It's not a stripped-down `def` — it's specifically for simple one-liners where naming the function adds no value: ```python # def version: def double(x): return x * 2 # lambda version — exactly equivalent: double = lambda x: x * 2 # lambda with two arguments: add = lambda x, y: x + y add(3, 4) # 7 # lambda with default: greet = lambda name, greeting='Hello': f'{greeting}, {name}!' greet('Alice') # 'Hello, Alice!' greet('Bob', 'Hi') # 'Hi, Bob!' ``` Lambda is most useful as an inline argument — e.g. `key=lambda x: x[1]`. **map() — transform every element** ```python # map returns a map object — not a list! result = map(str, [1, 2, 3]) # <map object at 0x...> list(result) # ['1', '2', '3'] # With a lambda: squares = list(map(lambda x: x ** 2, [1, 2, 3, 4])) # [1, 4, 9, 16] # map with two iterables: sums = list(map(lambda a, b: a + b, [1, 2, 3], [10, 20, 30])) # [11, 22, 33] # map exhausts after first iteration — convert to list if you need to reuse: m = map(str, range(5)) first = list(m) # ['0', '1', '2', '3', '4'] second = list(m) # [] — already exhausted! ``` **filter() — keep elements that match a predicate** ```python # filter also returns an iterator — wrap in list() to see results evens = list(filter(lambda x: x % 2 == 0, range(10))) # [0, 2, 4, 6, 8] # filter(None, ...) removes falsy values: data = [0, 1, '', 'hello', None, True, [], [1]] truthy = list(filter(None, data)) # [1, 'hello', True, [1]] ``` **functools.reduce() — fold a sequence into one value** `reduce` is NOT a built-in in Python 3 — import it from `functools`: ```python from functools import reduce product = reduce(lambda acc, x: acc * x, [1, 2, 3, 4, 5]) # 120 (1*2*3*4*5) # With initial value (avoids errors on empty sequences): total = reduce(lambda acc, x: acc + x, [], 0) # 0 — safe, not error ```

lambda as key=, the operator module, and named functions vs lambda

#
**lambda as key= function** The most common use of lambda in Python is as the `key=` argument for `sorted()`, `max()`, `min()`, `groupby()`, etc.: ```python students = [('Alice', 85), ('Bob', 72), ('Carol', 91)] # Sort by score (second element) sorted(students, key=lambda s: s[1]) # [('Bob', 72), ('Alice', 85), ('Carol', 91)] # Highest scorer max(students, key=lambda s: s[1]) # ('Carol', 91) # Sort strings case-insensitively sorted(['Banana', 'apple', 'Cherry'], key=lambda s: s.lower()) # ['apple', 'Banana', 'Cherry'] ``` **operator module — faster alternatives to lambda** For the common cases of getting an item by index or an object attribute, the `operator` module provides optimised callables that run faster than lambda: ```python import operator # operator.itemgetter — same as lambda x: x[key] sorted(students, key=operator.itemgetter(1)) # sort by index 1 # Works with multiple keys (returns tuple): records = [('Alice', 'NY', 85), ('Bob', 'LA', 85), ('Carol', 'NY', 91)] sorted(records, key=operator.itemgetter(2, 0)) # sort by score then name # operator.attrgetter — same as lambda x: x.attr from dataclasses import dataclass @dataclass class Student: name: str score: int students = [Student('Alice', 85), Student('Bob', 72)] sorted(students, key=operator.attrgetter('score')) # operator.methodcaller — same as lambda x: x.method() words = ['hello', 'WORLD', 'Python'] sorted(words, key=operator.methodcaller('lower')) # ['hello', 'Python', 'WORLD'] ``` **Named functions vs lambda — when each wins** ```python # Lambda wins: short, inline, used once sorted(data, key=lambda x: x['price'] * (1 - x['discount'])) # Named function wins: complex logic, reused, needs a docstring def effective_price(item): base = item['price'] discount = item.get('discount', 0) tax = item.get('tax', 0.2) return base * (1 - discount) * (1 + tax) sorted(data, key=effective_price) ``` PEP 8 discourages assigning lambda to a variable name (`double = lambda x: x * 2`) — use `def` instead for clarity and tracebacks.

map/filter vs comprehensions, functools.partial, and decision guide

#
**map/filter vs comprehensions — readability comparison** ```python numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # Double all even numbers — three ways: # 1. map + filter (nested, reads inside-out): result = list(map(lambda x: x * 2, filter(lambda x: x % 2 == 0, numbers))) # 2. Comprehension (reads left to right, most Pythonic): result = [x * 2 for x in numbers if x % 2 == 0] # 3. For loop (most explicit): result = [] for x in numbers: if x % 2 == 0: result.append(x * 2) # All three produce: [4, 8, 12, 16, 20] ``` Comprehensions are the standard Python style for transformation + filtering. **When map/filter still make sense** ```python # map with a built-in (no lambda) — concise and fast: names = list(map(str.upper, ['alice', 'bob', 'carol'])) # ['ALICE', 'BOB', 'CAROL'] # Same with a named function: def to_celsius(f): return (f - 32) * 5 / 9 temps_c = list(map(to_celsius, [32, 68, 212])) # [0.0, 20.0, 100.0] # Piping through multiple operations (functional style): pipeline = filter(None, map(str.strip, raw_lines)) ``` **functools extras worth knowing** ```python from functools import partial, lru_cache # partial — create a specialised version of a function: from functools import partial double = partial(operator.mul, 2) double(5) # 10 double(21) # 42 # lru_cache — memoize expensive functions: @lru_cache(maxsize=128) def fibonacci(n): if n < 2: return n return fibonacci(n - 1) + fibonacci(n - 2) fibonacci(100) # instant, not exponential ``` **Quick decision guide** ``` Task Preferred style ────────────────────────────────── ───────────────────────────────── Transform + filter a list List comprehension Transform with a named/built-in fn map() without lambda Filter only (no transform) filter() or comprehension Fold/accumulate to one value reduce() or explicit loop Inline sort key lambda or operator.itemgetter Reusable key function def (named function) ```
01

Double with map

#

Write a function that takes a list of numbers and returns a new list where each number is doubled. Use map() with a lambda.

def double_all(numbers):
    pass


result = double_all([1, 2, 3, 4, 5])
print(result)
Solution
def double_all(numbers):
    return list(map(lambda n: n * 2, numbers))


result = double_all([1, 2, 3, 4, 5])
print(result)
02

Filter positives

#

Write a function that takes a list of numbers and returns only the positive ones. Use filter() with a lambda.

def keep_positives(numbers):
    pass


result = keep_positives([3, -1, 4, -1, -5, 9, -2, 6])
print(result)
Solution
def keep_positives(numbers):
    return list(filter(lambda n: n > 0, numbers))


result = keep_positives([3, -1, 4, -1, -5, 9, -2, 6])
print(result)
03

Sort by length

#

Write a function that takes a list of strings and returns them sorted by length, shortest first. Use sorted() with a lambda key.

def sort_by_length(words):
    pass


result = sort_by_length(["banana", "fig", "apple", "kiwi"])
print(result)
Solution
def sort_by_length(words):
    return sorted(words, key=lambda w: len(w))


result = sort_by_length(["banana", "fig", "apple", "kiwi"])
print(result)
04

Product with reduce

#

Write a function that takes a list of numbers and returns their product (multiply all elements together). Use reduce() from functools.

from functools import reduce


def product(numbers):
    pass


result = product([1, 2, 3, 4, 5])
print(result)
Solution
from functools import reduce


def product(numbers):
    return reduce(lambda acc, n: acc * n, numbers)


result = product([1, 2, 3, 4, 5])
print(result)
05

Apply a discount

#

Write a function that takes a list of prices and a discount percentage, and returns a new list with the discount applied to each price. Use map() with a lambda.

def apply_discount(prices, discount_percent):
    pass


result = apply_discount([100, 200, 50, 80], 10)
print(result)
Solution
def apply_discount(prices, discount_percent):
    return list(map(lambda p: p * (1 - discount_percent / 100), prices))


result = apply_discount([100, 200, 50, 80], 10)
print(result)
06

Filter even, square the rest

#

Write a function that takes a list of numbers, removes the even ones, and returns the squares of what remains. Chain filter() and map().

def odd_squares(numbers):
    pass


result = odd_squares([1, 2, 3, 4, 5, 6, 7])
print(result)
Solution
def odd_squares(numbers):
    return list(map(lambda n: n ** 2, filter(lambda n: n % 2 != 0, numbers)))


result = odd_squares([1, 2, 3, 4, 5, 6, 7])
print(result)
07

Sort objects by attribute

#

Write a function that takes a list of dictionaries, each with 'name' and 'score' keys, and returns the list sorted by score in descending order.

def sort_by_score(players):
    pass


players = [
    {"name": "Alice", "score": 82},
    {"name": "Bob", "score": 95},
    {"name": "Carol", "score": 71},
]
result = sort_by_score(players)
print(result)
Solution
def sort_by_score(players):
    return sorted(players, key=lambda p: p["score"], reverse=True)


players = [
    {"name": "Alice", "score": 82},
    {"name": "Bob", "score": 95},
    {"name": "Carol", "score": 71},
]
result = sort_by_score(players)
print(result)
08

Maximum by key

#

Write a function that takes a list of strings and returns the longest one. Use max() with a lambda key.

def longest_word(words):
    pass


result = longest_word(["cat", "elephant", "ox", "hippopotamus"])
print(result)
Solution
def longest_word(words):
    return max(words, key=lambda w: len(w))


result = longest_word(["cat", "elephant", "ox", "hippopotamus"])
print(result)
09

Filter by multiple conditions

#

Write a function that takes a list of numbers and returns only those that are both positive and even.

def positive_evens(numbers):
    pass


result = positive_evens([-4, 3, -2, 8, 0, 6, -7, 10])
print(result)
Solution
def positive_evens(numbers):
    return list(filter(lambda n: n > 0 and n % 2 == 0, numbers))


result = positive_evens([-4, 3, -2, 8, 0, 6, -7, 10])
print(result)
10

Cumulative sum with reduce

#

Write a function that takes a list of numbers and returns the largest sum you can reach by adding elements from left to right (i.e., the maximum value of any prefix sum). Use reduce() from functools.

from functools import reduce


def max_prefix_sum(numbers):
    pass


result = max_prefix_sum([1, -3, 2, 5, -1, 3])
print(result)
Solution
from functools import reduce


def max_prefix_sum(numbers):
    prefix_sums = []
    reduce(lambda acc, n: (prefix_sums.append(acc + n) or (acc + n)), numbers, 0)
    return max(prefix_sums)

# Or more clearly:
def max_prefix_sum(numbers):
    total = 0
    best = 0
    for n in numbers:
        total += n
        best = max(best, total)
    return best


result = max_prefix_sum([1, -3, 2, 5, -1, 3])
print(result)