Python · Синтаксис · Промежуточный

lambda, map, filter, reduce

10 задач

Функциональные инструменты для преобразования и фильтрации коллекций без явных циклов.

Синтаксис lambda, map() и filter() возвращают итераторы, functools.reduce

#
**lambda — анонимные функции** `lambda` — это однострочная анонимная функция с единственным выражением. Это не упрощённый `def` — она предназначена для простых однострочных случаев, где именование функции не добавляет ценности: ```python # Версия с def: def double(x): return x * 2 # Версия с lambda — полностью эквивалентна: double = lambda x: x * 2 # lambda с двумя аргументами: add = lambda x, y: x + y add(3, 4) # 7 # lambda со значением по умолчанию: greet = lambda name, greeting='Привет': f'{greeting}, {name}!' greet('Алиса') # 'Привет, Алиса!' greet('Боб', 'Привет') # 'Привет, Боб!' ``` Lambda наиболее полезна как встроенный аргумент — например, `key=lambda x: x[1]`. **map() — преобразовать каждый элемент** ```python # map возвращает объект map — не список! result = map(str, [1, 2, 3]) # <map object at 0x...> list(result) # ['1', '2', '3'] # С lambda: squares = list(map(lambda x: x ** 2, [1, 2, 3, 4])) # [1, 4, 9, 16] # map с двумя итерируемыми: sums = list(map(lambda a, b: a + b, [1, 2, 3], [10, 20, 30])) # [11, 22, 33] # map исчерпывается после первой итерации — преобразуй в список для повторного использования: m = map(str, range(5)) first = list(m) # ['0', '1', '2', '3', '4'] second = list(m) # [] — уже исчерпан! ``` **filter() — оставить элементы, соответствующие предикату** ```python # filter тоже возвращает итератор — оборачивай в list() для результатов evens = list(filter(lambda x: x % 2 == 0, range(10))) # [0, 2, 4, 6, 8] # filter(None, ...) удаляет ложные значения: data = [0, 1, '', 'hello', None, True, [], [1]] truthy = list(filter(None, data)) # [1, 'hello', True, [1]] ``` **functools.reduce() — свернуть последовательность в одно значение** `reduce` НЕ является встроенной в Python 3 — импортируй из `functools`: ```python from functools import reduce product = reduce(lambda acc, x: acc * x, [1, 2, 3, 4, 5]) # 120 (1*2*3*4*5) # С начальным значением (избегает ошибок на пустых последовательностях): total = reduce(lambda acc, x: acc + x, [], 0) # 0 — безопасно, не ошибка ```

lambda как key=, модуль operator и именованные функции vs lambda

#
**lambda как функция key=** Наиболее распространённое применение lambda в Python — как аргумент `key=` для `sorted()`, `max()`, `min()`, `groupby()` и т.д.: ```python students = [('Alice', 85), ('Bob', 72), ('Carol', 91)] # Сортировать по баллу (второй элемент) sorted(students, key=lambda s: s[1]) # [('Bob', 72), ('Alice', 85), ('Carol', 91)] # Наивысший балл max(students, key=lambda s: s[1]) # ('Carol', 91) # Сортировать строки без учёта регистра sorted(['Banana', 'apple', 'Cherry'], key=lambda s: s.lower()) # ['apple', 'Banana', 'Cherry'] ``` **Модуль operator — более быстрые альтернативы lambda** Для распространённых случаев получения элемента по индексу или атрибуту объекта модуль `operator` предоставляет оптимизированные callable, работающие быстрее lambda: ```python import operator # operator.itemgetter — то же, что lambda x: x[key] sorted(students, key=operator.itemgetter(1)) # сортировать по индексу 1 # Работает с несколькими ключами (возвращает кортеж): records = [('Alice', 'NY', 85), ('Bob', 'LA', 85), ('Carol', 'NY', 91)] sorted(records, key=operator.itemgetter(2, 0)) # по баллу, затем по имени # operator.attrgetter — то же, что 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 — то же, что lambda x: x.method() words = ['hello', 'WORLD', 'Python'] sorted(words, key=operator.methodcaller('lower')) # ['hello', 'Python', 'WORLD'] ``` **Именованные функции vs lambda — когда что лучше** ```python # Lambda лучше: короткая, встроенная, используется один раз sorted(data, key=lambda x: x['price'] * (1 - x['discount'])) # Именованная функция лучше: сложная логика, повторно используется 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 не рекомендует присваивать lambda переменной (`double = lambda x: x * 2`) — вместо этого используй `def`.

map/filter vs comprehension, functools.partial и гид по выбору

#
**map/filter vs comprehension — сравнение читаемости** ```python numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # Удвоить все чётные числа — три способа: # 1. map + filter (вложено, читается изнутри наружу): result = list(map(lambda x: x * 2, filter(lambda x: x % 2 == 0, numbers))) # 2. Comprehension (читается слева направо, наиболее Pythonic): result = [x * 2 for x in numbers if x % 2 == 0] # 3. Цикл for (наиболее явный): result = [] for x in numbers: if x % 2 == 0: result.append(x * 2) # Все три дают: [4, 8, 12, 16, 20] ``` Comprehension — стандартный стиль Python для преобразования + фильтрации. **Когда map/filter всё ещё имеют смысл** ```python # map со встроенной функцией (без lambda) — лаконично и быстро: names = list(map(str.upper, ['alice', 'bob', 'carol'])) # ['ALICE', 'BOB', 'CAROL'] # То же с именованной функцией: def to_celsius(f): return (f - 32) * 5 / 9 temps_c = list(map(to_celsius, [32, 68, 212])) # [0.0, 20.0, 100.0] # Конвейер через несколько операций (функциональный стиль): pipeline = filter(None, map(str.strip, raw_lines)) ``` **Полезное из functools** ```python from functools import partial, lru_cache # partial — создать специализированную версию функции: import operator double = partial(operator.mul, 2) double(5) # 10 double(21) # 42 # lru_cache — мемоизировать затратные функции: @lru_cache(maxsize=128) def fibonacci(n): if n < 2: return n return fibonacci(n - 1) + fibonacci(n - 2) fibonacci(100) # мгновенно, не экспоненциально ``` **Краткий гид по выбору** ``` Задача Предпочтительный стиль ────────────────────────────────── ───────────────────────────────── Преобразовать + отфильтровать список List comprehension Преобразовать с именованной/встроенной map() без lambda Только фильтрация (без преобразования) filter() или comprehension Свернуть/накопить в одно значение reduce() или явный цикл Встроенный ключ сортировки lambda или operator.itemgetter Функция ключа для повторного использования def (именованная функция) ```
01

Удвоение через map

#

Напишите функцию, которая принимает список чисел и возвращает новый список, где каждое число удвоено. Используйте map() с лямбдой.

def double_all(numbers):
    pass


result = double_all([1, 2, 3, 4, 5])
print(result)
Решение
def double_all(numbers):
    return list(map(lambda n: n * 2, numbers))


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

Фильтрация положительных

#

Напишите функцию, которая принимает список чисел и возвращает только положительные. Используйте filter() с лямбдой.

def keep_positives(numbers):
    pass


result = keep_positives([3, -1, 4, -1, -5, 9, -2, 6])
print(result)
Решение
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

Сортировка по длине

#

Напишите функцию, которая принимает список строк и возвращает их отсортированными по длине, от коротких к длинным. Используйте sorted() с лямбдой key.

def sort_by_length(words):
    pass


result = sort_by_length(["banana", "fig", "apple", "kiwi"])
print(result)
Решение
def sort_by_length(words):
    return sorted(words, key=lambda w: len(w))


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

Произведение через reduce

#

Напишите функцию, которая принимает список чисел и возвращает их произведение (перемножает все элементы). Используйте reduce() из functools.

from functools import reduce


def product(numbers):
    pass


result = product([1, 2, 3, 4, 5])
print(result)
Решение
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

Применить скидку

#

Напишите функцию, которая принимает список цен и процент скидки и возвращает новый список со скидкой, применённой к каждой цене. Используйте map() с лямбдой.

def apply_discount(prices, discount_percent):
    pass


result = apply_discount([100, 200, 50, 80], 10)
print(result)
Решение
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() и map().

def odd_squares(numbers):
    pass


result = odd_squares([1, 2, 3, 4, 5, 6, 7])
print(result)
Решение
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

Сортировка объектов по атрибуту

#

Напишите функцию, которая принимает список словарей с ключами 'name' и 'score', и возвращает список, отсортированный по score в порядке убывания.

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)
Решение
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

Максимум по ключу

#

Напишите функцию, которая принимает список строк и возвращает самую длинную из них. Используйте max() с лямбдой key.

def longest_word(words):
    pass


result = longest_word(["cat", "elephant", "ox", "hippopotamus"])
print(result)
Решение
def longest_word(words):
    return max(words, key=lambda w: len(w))


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

Фильтрация по нескольким условиям

#

Напишите функцию, которая принимает список чисел и возвращает только те, которые одновременно положительные и чётные.

def positive_evens(numbers):
    pass


result = positive_evens([-4, 3, -2, 8, 0, 6, -7, 10])
print(result)
Решение
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

Максимальная префиксная сумма через reduce

#

Напишите функцию, которая принимает список чисел и возвращает наибольшую сумму, которую можно получить, добавляя элементы слева направо (максимальное значение любой префиксной суммы). Используйте reduce() из functools.

from functools import reduce


def max_prefix_sum(numbers):
    pass


result = max_prefix_sum([1, -3, 2, 5, -1, 3])
print(result)
Решение
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)

# Или понятнее:
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)