Теория
Числа в файле
В задании этого типа дан файл: в каждой строке записано одно целое число. Если в файле пять строк, перед нами пять чисел в том же порядке, в каком они записаны. Порядок важен: число после другого может образовать с ним пару или тройку.
Такой упорядоченный ряд значений называют числовой последовательностью. Здесь «последовательность» нужно понимать буквально: важны и сами числа, и их очередь. Например, для строк 4, −2, 7 последовательность именно такая: 4, −2, 7. Если поменять строки местами, значения останутся, но соседства изменятся.
Python сначала читает строки, затем превращает каждую в целое число. Этот способ подробно разобран в уроке мини-курса «Чтение данных из файла». Здесь также важно сохранить порядок прочитанных чисел, поэтому соберём их в список. Квадратные скобки создают список; если нужно освежить эту тему, смотри урок «Списки».
В записи for line in file слова означают: повторить действие для каждой строки файла. Такой повторяющийся порядок команд называется циклом. Ниже цикл будет брать по очереди числа из уже созданного списка.
В записи целиком это читается так: для каждой строки выполнить int(line) и положить получившееся число в новый список. Строки не склеиваются и не сортируются — каждое значение превращается в число и сохраняет своё место.
with open("numbers.txt", encoding="utf-8") as file: numbers = [int(line) for line in file] print(numbers)Если в файле стоят строки 12, −3 и 8, переменная numbers получит список чисел в том же порядке. Цикл потом сможет проверять каждое значение. О том, как читать файл строка за строкой и получать из текста числа, рассказывает связанный урок по работе с файлами.
- Первая строка станет целым числом
12. - Вторая строка станет целым числом
−3. - Третья строка станет целым числом
8. - Получится список [12, −3, 8]; отрицательное число и порядок сохранились.
Отдельные числа
Иногда условие относится к одному числу: например, нужно посчитать положительные числа, которые делятся на три. Берём числа по одному, проверяем каждое и увеличиваем счётчик, если ответ на проверку «да». Счётчик — переменная, где хранится, сколько подходящих чисел уже встретилось. О нём и переменных, которые меняются в цикле, подробнее рассказывает урок о счётчиках и накопителях.
Проверку «подходит или нет» назовём условием отбора. Название новое, но смысл знакомый: для каждого числа Python задаёт вопрос с ответом «да» или «нет». Например, сразу после словесного условия «положительное и делится на три» можно записать: number > 0 and number % 3 == 0.
- Начинаем со счётчика
count = 0: пока ещё ничего не проверили. - Число
−6не положительное — пропускаем его. - Число
3подходит, счётчик становится равен1. - Число
8не делится на три, а12подходит: теперь счётчик равен2. - Число
−3отрицательное. Ответ —2.
numbers = [-6, 3, 8, 12, -3]count = 0 for number in numbers: if number > 0 and number % 3 == 0: count += 1 print(count) # 2Остаток от деления на три записывается знаком %; нулевой остаток означает, что число делится нацело. Слово and требует, чтобы обе проверки оказались верными. Запись count += 1 прибавляет к счётчику единицу.
В другой задаче нужно найти не количество, а самое большое или самое маленькое подходящее число. Эти значения называют максимумом и минимумом; вместе — экстремумом. Начни с первого числа, которое прошло условие. Затем сравнивай с ним остальные подходящие значения и заменяй ответ, если встретилось большее или меньшее. Такой выбор результата разбирается и в уроке «Отбор результата».
- Число
−8чётное, но не положительное — оно не подходит. - Первое подходящее число —
14. Запишем его как текущий максимум. - Число
6меньше14; максимум не меняется. - Число
−2отрицательное, а11нечётное. Ответ остаётся равен14.
Соседние пары
Иногда условие касается двух чисел, которые стоят рядом в файле. Такую пару называют соседней. В списке [5, 2, 9, 4] пары такие: (5, 2), (2, 9) и (9, 4). Пара (5, 9) не соседняя: между числами в файле стоит 2.
Чтобы записать пару в коде, нужно знать порядковый номер числа в списке. Такой номер называется индексом. В Python индексы начинаются с нуля: у первого числа индекс 0, у второго — 1. Если индекс первого числа пары — i, то второе находится по индексу i + 1. Подробнее о списках и обращении к их элементам — в уроке «Списки».
У последнего числа уже нет соседа справа. Поэтому начинаем пару с индексов от нуля до предпоследней позиции. Функция len сообщает длину списка, а range(len(numbers) - 1) выдаёт все индексы начала пары.
- С индекса 0 получаем
(5, 2). Пара подходит. - С индекса 1 получаем
(2, 9). Она тоже подходит. - С индекса 2 получаем
(9, 4). Это последняя пара; она подходит. - Всего три пары, значит ответ —
3.
numbers = [5, 2, 9, 4]count = 0 for i in range(len(numbers) - 1): left = numbers[i] right = numbers[i + 1] if left % 2 != right % 2: count += 1 print(count) # 3Переменные left и right временно называют числа в паре так, чтобы проверку было легче читать. Пара (5, 2) и пара (2, 9) используют число 2 обе — это правильно: мы считаем все соседства, а не стараемся избегать повторов.
- Сумма пары (4, 10) равна 14. Пока это лучший результат.
- Пара (10, −3) даёт 7, меньше 14.
- Пара (−3, 8) даёт 5. Ответ остаётся равен
14.
Соседние тройки
Если условие касается трёх чисел подряд, передвигаем начало группы по тем местам, где справа помещаются ещё два числа. Для списка [2, 7, 4, 9, 6] это тройки (2, 7, 4), (7, 4, 9) и (4, 9, 6). Они тоже пересекаются: число 4 входит в каждую.
Начало тройки имеет индекс i, а остальные числа стоят на местах i + 1 и i + 2. Последний допустимый индекс начала — за два места до конца. Поэтому цикл записывают как range(len(numbers) - 2).
- Первая тройка (−5, 8, 2) имеет сумму 5 и подходит.
- Следующая тройка (8, 2, −4) имеет сумму 6 и подходит.
- Последняя тройка (2, −4, 7) имеет сумму 5 и подходит.
- Найдено три тройки, ответ —
3.
numbers = [-5, 8, 2, -4, 7]count = 0 for i in range(len(numbers) - 2): total = numbers[i] + numbers[i + 1] + numbers[i + 2] if total > 0: count += 1 print(count) # 3Здесь условие «сумма больше нуля» записано как total > 0. Если бы подошёл и ноль, нужно было бы написать total >= 0. Внимательно различай слова «больше» и «не меньше», «меньше» и «не больше»: строгие и нестрогие сравнения дают разные ответы.
В следующей задаче проверяется не сумма всей тройки: важно, насколько её середина выше двух соседей. Для средней позиции списка удобнее оставить три имени. Если середина стоит под индексом i, то левое число лежит под индексом i - 1, сама середина — под i, а правое число — под i + 1. Первый элемент не может быть серединой: у него нет левого соседа. Последний тоже не подходит, потому что у него нет правого.
- При
i = 1числа слева, в середине и справа —4, 9, 3. Проверки9 > 4и9 > 3обе верны: считаем эту тройку. - При
i = 2середина равна 3, она не больше ни одного из соседей. - При
i = 3середина 7 больше левого числа 3, но равна правому числу 7. Строгое сравнение не проходит. - При
i = 4середина 7 равна левому числу 7, поэтому эта тройка тоже не подходит. - При
i = 5середина 2 меньше обоих соседей. Приi = 6тройка2, 10, 1подходит. Ответ —2.
numbers = [4, 9, 3, 7, 7, 2, 10, 1]count = 0 for i in range(1, len(numbers) - 1): left = numbers[i - 1] middle = numbers[i] right = numbers[i + 1] if middle > left and middle > right: count += 1 print(count) # 2Знак > означает «строго больше»: равенство соседу не подходит. В цикле начало равно 1, потому что только со второго числа появляется левый сосед; остановка перед последним индексом оставляет правого соседа. Поэтому в каждой строке кода существуют все три значения left, middle и right.
- Первая тройка (1, 5, −2) имеет сумму 4. Запишем её как лучший результат.
- Последняя тройка (5, −2, 8) имеет сумму 11.
- 11 больше 4, поэтому ответ —
11.
i, i + 1 и i + 2. Слишком позднее начало заставит Python обратиться к позиции, которой нет. Для группы из трёх чисел оставь после начала ещё два места.Когда нужны два прохода
Бывает, что пару нужно сравнить со средней величиной всех чисел файла. Среднее арифметическое — это сумма всех чисел, разделённая на их количество. Пока не просмотрен весь список, среднее неизвестно, а значит, первую пару ещё нельзя проверить.
Сначала полностью просматриваем список, чтобы найти нужную величину, затем ещё раз просматриваем его и проверяем пары. Каждый полный просмотр называется проходом. Повторно открывать файл необязательно: прочитанные числа уже лежат в списке.
В первом цикле можно накопить сумму, а потом разделить её на количество чисел. Функция sum(numbers) складывает значения списка, а len(numbers) сообщает, сколько их. Это приём из урока о счётчиках и накопителях. Во втором цикле будут проверяться пары. Если нужен разбор того, как после цикла оставить правильный результат, поможет урок «Отбор результата».
- В первом проходе складываем все значения:
1 + 4 + 0 + 2 + 13 = 20. - В списке пять чисел, поэтому среднее равно
20 / 5 = 4. - Во втором проходе проверяем пары по очереди: сумма пары (1, 4) равна 5 и подходит; сумма (4, 0) равна 4 — это ровно среднее, поэтому пара не подходит; сумма (0, 2) равна 2 и меньше среднего; сумма (2, 13) равна 15 и подходит.
- Счётчик увеличился для первой и последней пары. Ответ и вывод программы —
2.
numbers = [1, 4, 0, 2, 13]average = sum(numbers) / len(numbers) # 4count = 0 for i in range(len(numbers) - 1): if numbers[i] + numbers[i + 1] > average: count += 1 print(count) # 2Среднее здесь — опорное значение: оно вычислено по всему файлу и помогает решить, какие пары засчитать. Сама пара выбирается по соседству, а не по положению в середине списка. Это два разных свойства, не смешивай их.
Иногда сначала отбирают несколько чисел, находят среди них максимум или минимум, а потом проверяют пары или тройки. Тогда нужны последовательные проходы: сначала вычисли величину, от которой зависит условие, и только затем применяй это условие к соседствам. Если для решения нужны три отдельных этапа, не пытайся уместить их в один цикл ценой использования ещё неизвестного значения.
Проверка границ и ответа
Перед запуском спроси себя: что считается одним кандидатом, когда перебор заканчивается и какие величины уже известны. Эти вопросы помогают заметить ошибку на последнем числе: программа может выполняться без сбоя, но пропускать крайнюю пару или тройку.
- Отдельные числа. Проверь все значения, от первого до последнего.
- Пара. Первое число пары может стоять до предпоследней позиции; второе — справа от него.
- Тройка. После начала группы должны оставаться ещё две позиции.
- Общая характеристика. Сначала вычисли её по всем нужным данным, потом используй для отбора.
- Максимум или минимум. Начни с подходящего значения из файла, а не с придуманного числа.
Проверим тройки на коротком наборе [1, 8, 3, 10]. Нужно найти наибольшую положительную сумму соседней тройки. У первой тройки начало с индексом 0, у второй — с индексом 1. Начало с индексом 2 уже не подходит: от этой позиции до конца есть только два числа всего, а для тройки нужны три. Ручной перебор — простой способ увидеть все группы до запуска программы.
- С начала 0 получаем (1, 8, 3); сумма равна
12. - С начала 1 получаем (8, 3, 10); сумма равна
21. - Другого допустимого начала нет: для позиции 2 не останется трёх чисел.
- Обе суммы положительные, а 21 больше 12. Ответ —
21.
На настоящем файле не нужно вручную перебирать сотни чисел. Короткий пример проверяет сам способ: правильно ли начинается цикл, включает ли последнюю группу и обновляется ли ответ. Перед отправкой ещё раз прочитай сравнение в условии и убедись, что начальное значение максимума или минимума взято из подходящих чисел.
На экзамене
Не начинай с шаблона кода. Сначала отметь, что является кандидатом: отдельное число, соседняя пара или соседняя тройка. Затем выпиши условие отбора и выясни, зависит ли оно от всего файла. Если зависит, сначала вычисли нужную общую величину.
- Прочитай данные. Одна строка — одно целое число; порядок строк может быть важен.
- Запиши проверки. Отдельно отметь требования к числам и к паре или тройке.
- Выбери границу. Для группы оставь справа место для каждого её числа.
- Найди ответ. Считай подходящие группы или обновляй максимум/минимум после проверки условия.
- Проверь вручную. На коротком списке выпиши кандидатов и сравни с перебором программы.
Особенно внимательно различай «больше» и «не меньше», считай пересекающиеся группы, не соединяй первое и последнее числа файла и не выбирай начальный максимум наугад. Практика идёт от отдельного числа к задачам с несколькими зависимыми условиями.
Практика
Практика временно недоступна. Можно продолжить читать теорию.
Итог
Что получилось
Теперь ты умеешь читать числа из файла, проверять отдельные значения, перебирать соседние пары и тройки, а также сначала находить общую характеристику данных и использовать её при отборе. Перед ответом проверь последнюю допустимую позицию начала группы и слова, задающие строгость сравнения.
Решай задачи по порядку. Если ошибся в границе или выборе результата, вернись к нужному примеру и повтори его на коротком списке. Ссылки на работу с файлами, списки, счётчики и накопители и отбор результата объясняют нужные Python-приёмы; проходить весь курс до этой темы не нужно.