✅ Решения заданий

⚡ Решения в двух словах

  • 1.1 — предикат + list comprehension.
  • 1.2 — filter(lambda ..., nums).
  • 2.1–2.3 — передача критерия как параметра.
  • 3 — reduce для произведения.
  • 4 — sorted(words, key=len).
  • 5 — сортировка по времени и накопление суммы.
  • 6 — среднее и сортировка словаря.
  • 7 — sorted(words, key=lambda w: sum(ord(c) for c in w)).
  • 8 — композиция функций.
⚠️ Рекомендация: попробуйте решить задания самостоятельно, прежде чем смотреть ответы. Решения — это последняя инстанция, когда собственные попытки исчерпаны.

Решение задания 1.1. Фильтрация чётных с функцией

# task1_1_solution.py
from typing import Callable


def is_even(n: int) -> bool:
    """Проверяет, является ли число чётным."""
    return n % 2 == 0


def filter_by_predicate(
    predicate: Callable[[int], bool],
    numbers: list[int]
) -> list[int]:
    """Возвращает элементы, для которых predicate вернул True."""
    return [n for n in numbers if predicate(n)]


nums = [1, 2, 3, 4, 5, 6]
print(filter_by_predicate(is_even, nums))

Логика решения: предикат отделён от фильтрации, поэтому функцию filter_by_predicate можно переиспользовать с любым условием.

Решение задания 1.2. Фильтрация чётных с filter

# task1_2_solution.py
nums = [1, 2, 3, 4, 5, 6]
evens = list(filter(lambda x: x % 2 == 0, nums))
print(evens)

Логика решения: filter принимает функцию и итерируемый объект, возвращая только элементы, прошедшие проверку. Результат обязательно преобразуем в список для вывода.

Решение задания 2.1. Фильтрация строк по длине

# task2_1_solution.py
def filter_long_words(words: list[str], min_len: int = 3) -> list[str]:
    """Возвращает слова длиной больше min_len."""
    return [word for word in words if len(word) > min_len]


words = ["hi", "Hello", "a", "python", "Ok"]
print(filter_long_words(words))

Логика решения: параметр min_len имеет значение по умолчанию 3, что соответствует условию задачи 2.1.

Решение задания 2.2. Фильтрация по настраиваемой длине

# task2_2_solution.py
def filter_by_length(
    words: list[str],
    min_len: int = 3
) -> list[str]:
    """Возвращает слова длиной не меньше min_len."""
    return [word for word in words if len(word) >= min_len]


words = ["hi", "Hello", "a", "python", "Ok"]
min_len = 2
print(filter_by_length(words, min_len))

Логика решения: условие изменено на >=, чтобы слова длины 2 тоже попадали в результат. Параметр min_len передаётся явно.

Решение задания 2.3. Фильтрация по критерию

# task2_3_solution.py
from typing import Callable


def filter_words(
    words: list[str],
    predicate: Callable[[str], bool]
) -> list[str]:
    """Возвращает слова, удовлетворяющие переданному критерию."""
    return [word for word in words if predicate(word)]


words = ["hi", "Hello", "a", "python", "Ok", "Radar"]
print(filter_words(words, lambda w: w.istitle()))
print(filter_words(words, lambda w: len(w) == 1))
print(filter_words(words, lambda w: w[0].lower() == w[-1].lower()))

Логика решения: функция принимает критерий как аргумент. Лямбды покрывают три разных случая без дублирования кода.

Решение задания 3. Агрегирование списка

# task3_solution.py
from functools import reduce


def product(numbers: list[int]) -> int:
    """Возвращает произведение всех элементов списка."""
    return reduce(lambda acc, x: acc * x, numbers, 1)


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

Логика решения: reduce накапливает произведение, начиная с 1. Начальное значение защищает от ошибки на пустом списке.

Решение задания 4. Сортировка по длине

# task4_solution.py
def sort_by_length(words: list[str]) -> list[str]:
    """Сортирует слова по возрастанию длины."""
    return sorted(words, key=len)


words = ["apple", "banana", "kiwi", "grape"]
print(sort_by_length(words))

Логика решения: key=len вычисляет длину каждого слова, и сортировка происходит по этим числам.

Решение задания 5. Очередь с ограничением времени

# task5_solution.py
def schedule_within_limit(
    tasks: dict[str, int],
    time_limit: int
) -> dict[str, int]:
    """Возвращает задачи, которые укладываются в лимит времени."""
    sorted_tasks = sorted(tasks.items(), key=lambda item: item[1], reverse=True)
    selected: dict[str, int] = {}
    total = 0
    for name, duration in sorted_tasks:
        if total + duration <= time_limit:
            selected[name] = duration
            total += duration
    return selected


tasks = {"task1": 5, "task2": 3, "task3": 7, "task4": 2}
print(schedule_within_limit(tasks, 10))

Логика решения: задачи сортируются по убыванию времени. На каждом шаге добавляем самую долгую оставшуюся задачу, если она помещается в остаток лимита. Этот жадный подход даёт результат из примера: сначала берётся задача на 7 единиц, затем на 3, в сумме ровно 10.

Решение задания 6. Анализ оценок студентов

# task6_solution.py
def average_grades(students: list[dict]) -> dict[str, float]:
    """Возвращает словарь имя → средняя оценка, отсортированный по убыванию."""
    averages = {
        student["name"]: round(sum(student["grades"]) / len(student["grades"]), 2)
        for student in students
    }
    return dict(sorted(averages.items(), key=lambda item: item[1], reverse=True))


students = [
    {"name": "Alice", "grades": [90, 85, 88]},
    {"name": "Bob", "grades": [78, 81, 75]},
    {"name": "Charlie", "grades": [95, 92, 90]},
    {"name": "Diana", "grades": [88, 84, 82]}
]
print(average_grades(students))

Логика решения: сначала вычисляются средние значения через dict comprehension, затем словарь сортируется по значению в обратном порядке.

Решение задания 7. Сортировка по сумме кодов символов

# task7_solution.py
words = ["banana", "kiwi", "grapefruit", "apple"]
sorted_words = sorted(words, key=lambda word: sum(ord(c) for c in word))
print(sorted_words)

Логика решения: лямбда вычисляет сумму кодов символов каждого слова. sorted использует это значение как ключ. Решение умещается в одну строку.

Решение задания 8. Цепочка шифрования

# task8_solution.py
from typing import Callable


def to_uppercase(text: str) -> str:
    return text.upper()


def shift_encrypt(text: str, shift: int = 5) -> str:
    return "".join(chr(ord(c) + shift) for c in text)


def reverse_string(text: str) -> str:
    return text[::-1]


def encrypt(
    text: str,
    functions: list[Callable[[str], str]]
) -> str:
    """Последовательно применяет функции к строке."""
    result = text
    for func in functions:
        result = func(result)
    return result


sentence = "Functional programming is powerful"
functions = [to_uppercase, shift_encrypt, reverse_string]
print(encrypt(sentence, functions))

Логика решения: функция encrypt обобщена — она принимает любой список функций и применяет их последовательно. Это позволяет легко менять порядок или добавлять шаги шифрования.