{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "f88aff01",
   "metadata": {},
   "source": [
    "# Лабораторная работа 8\n",
    "\n",
    "## Функции высшего порядка и обработка последовательностей\n",
    "\n",
    "В этой лабораторной функции будут не только выполнять вычисления: их можно сохранять в переменных, передавать другим функциям и получать как результат работы функции. Списки не используйте. Там, где это существенно, условие прямо называет нужный инструмент.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f2239fa9",
   "metadata": {},
   "source": [
    "## Раздел 1. Распаковка и функции для обработки последовательностей\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2c85fd8a",
   "metadata": {},
   "source": [
    "**Задача 1. Цена с учётом скидки и налога**\n",
    "\n",
    "Опишите функцию `final_cost(price, discount_percent, tax_percent)`, возвращающую итоговую цену: сначала к базовой цене применяется скидка, затем начисляется налог на уменьшенную цену. Три вещественных числа вводить в одну строку через пробел. Поместить ввод данных прямо в вызов функции `final_cost`. Используйте распаковку результата `map` с помощью оператора `*`.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c0d6c7ef",
   "metadata": {},
   "outputs": [],
   "source": [
    "def final_cost(price, discount_percent, tax_percent):\n",
    "    ...\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cc278c4a",
   "metadata": {},
   "source": [
    "**Задача 2. Текст в коды символов**\n",
    "\n",
    "Опишите функцию `text_to_codes(text)`, которая возвращает строку с десятичными кодами символов исходного текста, разделёнными точкой с запятой. Например, для `A!` результат — `65;33`. Используйте `map`, `ord`, `str` и `join`; циклы не используйте.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c97fa4cb",
   "metadata": {},
   "outputs": [],
   "source": [
    "def text_to_codes(text):\n",
    "    return ...\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1966ea89",
   "metadata": {},
   "source": [
    "*Пример проверки.* Запустите ячейку с функцией, затем эту ячейку. Допишите еще несколько тестов.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "62639035",
   "metadata": {},
   "outputs": [],
   "source": [
    "assert text_to_codes('A!') == '65;33'\n",
    "assert text_to_codes('а') == str(ord('а'))\n",
    "assert text_to_codes('H3ll0') == '72;51;108;108;48'\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9708e46e",
   "metadata": {},
   "source": [
    "**Задача 3. Коды символов в текст**\n",
    "\n",
    "Опишите функцию `codes_to_text(codes)`, выполняющую обратное преобразование. Строка `codes` непустая и содержит корректные десятичные коды символов, разделённые точкой с запятой. Используйте `map`, `int`, `chr` и `join`; циклы не используйте.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "63b843c5",
   "metadata": {},
   "outputs": [],
   "source": [
    "def codes_to_text(codes):\n",
    "    return ...\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b960ba46",
   "metadata": {},
   "source": [
    "*Пример проверки.* Запустите ячейку с функцией, затем эту ячейку. Допишите еще несколько тестов.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "1d2616fc",
   "metadata": {},
   "outputs": [],
   "source": [
    "assert codes_to_text('65;33') == 'A!'\n",
    "assert codes_to_text(str(ord('я'))) == 'я'\n",
    "assert codes_to_text('72;51;108;108;48') == 'H3ll0'\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bf46f090",
   "metadata": {},
   "source": [
    "**Задача 4. Очистка имени пользователя**\n",
    "\n",
    "Опишите функцию `clean_login(text)`. Она должна перевести строку в нижний регистр и оставить только латинские буквы, цифры и символ `_`. Используйте `filter` и `lambda`; цикл не используйте. Считайте, что буквы во входной строке только латинские.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c8a4b5cb",
   "metadata": {},
   "outputs": [],
   "source": [
    "def clean_login(text):\n",
    "    ...\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fded8f80",
   "metadata": {},
   "source": [
    "**Задача 5. Проверка шестнадцатеричного токена**\n",
    "\n",
    "Опишите функцию `is_hex_token(token)`, возвращающую `True`, если строка имеет длину от 4 до 16, состоит только из шестнадцатеричных цифр `0`–`9`, `A`–`F`, `a`–`f`, содержит хотя бы одну цифру и хотя бы одну букву. Для проверок символов используйте `all`, `any` и `map`; циклы не используйте.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2c797d4a",
   "metadata": {},
   "outputs": [],
   "source": [
    "def is_hex_token(token):\n",
    "    ...\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dc5234f6",
   "metadata": {},
   "source": [
    "*Пример проверки.* Запустите ячейку с функцией, затем эту ячейку. Допишите еще несколько тестов.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "7f7d5d98",
   "metadata": {},
   "outputs": [],
   "source": [
    "assert is_hex_token('A3F09C')\n",
    "assert not is_hex_token('ABCDEF')\n",
    "assert not is_hex_token('12G4')\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a09f5c26",
   "metadata": {},
   "source": [
    "**Задача 6. Последовательные скидки**\n",
    "\n",
    "Опишите функцию `price_after_discounts(price, *discounts)`, применяющую к цене все скидки по очереди. Например, скидки 10% и 20% уменьшают цену `1000` до `720`, а не до `700`. Для последовательного применения скидок используйте `reduce` и `lambda`; циклы не используйте. Цена и хотя бы одна скидка вводятся **отдельно**.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4f4e85e9",
   "metadata": {},
   "outputs": [],
   "source": [
    "from functools import reduce\n",
    "\n",
    "def price_after_discounts(price, *discounts):\n",
    "    return ...\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ef4fc7e2",
   "metadata": {},
   "source": [
    "**Задача 7. Короткий числовой отпечаток текста**\n",
    "\n",
    "Опишите функцию `short_hash(text)`, вычисляющую число по правилу: для каждого следующего символа новое значение равно `(старое_значение * 31 + код_символа) % 1_000_000_007`. Начальное значение равно 0. Это упрощённый вариант полиномиального хеша; он не предназначен для защиты паролей. Используйте `reduce` и `lambda`; циклы не используйте.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8b915291",
   "metadata": {},
   "outputs": [],
   "source": [
    "#from functools import reduce\n",
    "\n",
    "def short_hash(text):\n",
    "    return ...\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f97674c1",
   "metadata": {},
   "source": [
    "## Раздел 2. Функция как аргумент\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0eef4b7a",
   "metadata": {},
   "source": [
    "**Задача 8. Таблица значений функции**\n",
    "\n",
    "Опишите функцию `print_table(start, end, action, name)`. Она должна вывести значения функции `action` для всех целых чисел от `start` до `end` включительно; `name` используется в пояснении вывода к каждой строке. В основной программе в качестве `name` передайте текст `Квадрат`, а в качестве `action` передайте анонимную функцию для вычисления квадрата числа. Затем отдельно выведите кубы чисел.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "54cd5b93",
   "metadata": {},
   "outputs": [],
   "source": [
    "def print_table(start, end, action, name):\n",
    "    ...\n",
    "\n",
    "# Квадраты\n",
    "\n",
    "\n",
    "# Кубы\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d0fbb3bf",
   "metadata": {},
   "source": [
    "**Задача 9. Подсчёт по условию**\n",
    "\n",
    "Опишите функцию `count_by_condition(start, end, condition)`, возвращающую количество целых чисел от `start` до `end` включительно, для которых функция `condition` возвращает `True`. Проверьте функцию: подсчитайте числа, которые делятся на введённый делитель и не оканчиваются цифрой 0. Условие передайте через `lambda`.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9fcfa4ea",
   "metadata": {},
   "outputs": [],
   "source": [
    "def count_by_condition(start, end, condition):\n",
    "    ...\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1e4675db",
   "metadata": {},
   "source": [
    "**Задача 10. Итерационный поиск квадратного корня**\n",
    "\n",
    "Опишите функцию `iterate(value, count, rule)`, которая `count` раз применяет функцию `rule` к значению `value` и возвращает результат. С её помощью приблизьте квадратный корень положительного числа `N` методом Ньютона. Начальное приближение — `N`, правило перехода: `(current + N / current) / 2`. Передайте правило как `lambda`-функцию. Число итераций вводится пользователем.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5edeaa5d",
   "metadata": {},
   "outputs": [],
   "source": [
    "from math import isclose\n",
    "\n",
    "def iterate(value, count, rule):\n",
    "    ...\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a0f8944b",
   "metadata": {},
   "source": [
    "*Пример проверки.* Здесь достаточно относительной погрешности: ожидаемое значение не близко к нулю. Допишите еще несколько тестов.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "df660104",
   "metadata": {},
   "outputs": [],
   "source": [
    "root_of_two = iterate(2.0, 5, ???) # вставьте подходящую лямбду на место ???\n",
    "assert isclose(root_of_two, 2 ** 0.5, rel_tol=1e-9)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a35ee9be",
   "metadata": {},
   "source": [
    "## Раздел 3. Локальные функции, фабрики и конвейеры\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6f0a648b",
   "metadata": {},
   "source": [
    "**Задача 11. Допустимые символы и скобки выражения**\n",
    "\n",
    "Опишите функцию `is_simple_expression(expression)`. Она возвращает `True`, если непустая строка содержит только цифры, пробелы, символы `+`, `-`, `*`, `/`, круглые скобки, а скобки правильно сбалансированы: их количество не становится отрицательным при просмотре слева направо и в конце равно нулю. Полную математическую корректность выражения проверять не нужно.\n",
    "\n",
    "Внутри функции определите локальную функцию `is_allowed(symbol)` для проверки допустимого символа. Используйте эту локальную функцию вместе с `all` и `map`.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9f70c75b",
   "metadata": {},
   "outputs": [],
   "source": [
    "def is_simple_expression(expression):\n",
    "    ...\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "797591af",
   "metadata": {},
   "source": [
    "**Задача 12. Самый частый значимый символ**\n",
    "\n",
    "Дана строка, содержащая хотя бы один непробельный символ. Найдите самый частый непробельный символ. При равной частоте выберите тот, который встречается раньше. Сначала отфильтруйте пробельные символы с помощью `filter`, затем примените `max` с параметром `key=text.count`. Здесь `text.count` передаётся встроенной функции как функция, задающая критерий выбора.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "df76d4bf",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "9907bd84",
   "metadata": {},
   "source": [
    "**Задача 13. Фабрика калибровки датчика**\n",
    "\n",
    "Опишите функцию `make_calibrator(raw_start, raw_end, value_start, value_end)`. Она возвращает функцию `calibrate(raw_value)`, которая линейно переводит показание датчика из диапазона `raw_start..raw_end` в физическую величину диапазона `value_start..value_end`. Например, датчик с показаниями от 0 до 10 может соответствовать температуре от -50 до 50.\n",
    "\n",
    "Вложенная функция должна использовать параметры внешней функции. Значения `raw_start` и `raw_end` различны.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8d2a13ad",
   "metadata": {},
   "outputs": [],
   "source": [
    "def make_calibrator(raw_start, raw_end, value_start, value_end):\n",
    "    ...\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b10f44e6",
   "metadata": {},
   "source": [
    "*Пример проверки.* Для вещественного результата используйте `isclose`. Допишите еще несколько тестов.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "019afc65",
   "metadata": {},
   "outputs": [],
   "source": [
    "from math import isclose\n",
    "\n",
    "sensor_to_temperature = make_calibrator(0, 10, -50, 50)\n",
    "assert isclose(sensor_to_temperature(2.5), -25.0, rel_tol=1e-9)\n",
    "assert isclose(sensor_to_temperature(10), 50.0, rel_tol=1e-9)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9f94a7ab",
   "metadata": {},
   "source": [
    "**Задача 14. Фабрика конвейеров преобразований**\n",
    "\n",
    "Опишите функцию `make_pipeline(*steps)`, возвращающую функцию `pipeline(value)`. Полученная функция должна последовательно применять к `value` все функции из `steps` и возвращать итог. Вложенная функция здесь полезна: она хранит набор заранее настроенных шагов обработки и может многократно применяться к разным значениям.\n",
    "\n",
    "Проверьте свою функцию на строке: удалите пробелы по краям, переведите текст в верхний регистр и добавьте в конце `!`.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2ab2719c",
   "metadata": {},
   "outputs": [],
   "source": [
    "def make_pipeline(*steps):\n",
    "    ...\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "aa93369c",
   "metadata": {},
   "source": [
    "*Пример проверки.* Допишите еще несколько тестов.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "b258f533",
   "metadata": {},
   "outputs": [],
   "source": [
    "prepare = make_pipeline(str.strip, str.upper, lambda text: text + '!')\n",
    "assert prepare('  готово ') == 'ГОТОВО!'\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b5f3ad44",
   "metadata": {},
   "source": [
    "**Задача 15. Конвейер для метки статьи**\n",
    "\n",
    "Используйте `make_pipeline` из предыдущей задачи, чтобы создать функцию `to_slug`. Она должна: удалить пробелы по краям, перевести строку в нижний регистр, заменить каждый пробел на дефис и удалить все символы, кроме букв, цифр и дефиса. Для последнего шага используйте `filter` и `lambda`. Примените созданную функцию к введённому тексту.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "242bd5b3",
   "metadata": {},
   "outputs": [],
   "source": [
    "to_slug = make_pipeline(...)\n",
    "\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python [conda env:base] *",
   "language": "python",
   "name": "conda-base-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
