Itertools на Python: разбейте поток на партии с лимитом

Напишите решение на Python и проверьте его на странице.

Другие упражнения по этой теме: Itertools в Python: задачи на комбинации, groupby и ленивые потоки.

Партии почтового терминала

На сортировочном терминале непрерывный поток посылок нарезается на партии фиксированного размера для автоматического сканера. Терминал отсчитывает полные пачки до тех пор, пока не наберётся заданный лимит таких партий либо пока во входном потоке не закончатся посылки.

Если установленный лимит полных партий достигнут, конвейер останавливается немедленно. Система не считывает из источника следующие элементы, а отдельный буфер ручной сортировки остаётся пустым. Если же поток исчерпался сам собой до выполнения лимита и в конце осталась незавершённая пачка, она не должна потеряться — эти посылки отправляются в буфер ручной сортировки как хвостовой остаток.

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

Что уже дано

В редакторе представлена заготовка функции postal_batches(source, batch_size, limit_batches). Вспомогательные функции make_postal_source и observe_postal_source уже доступны в среде исполнения для отладки и запуска проверочного примера, реализовывать их заново не требуется.

Что нужно сделать

Реализуйте функцию postal_batches(source, batch_size, limit_batches).

Функция принимает три аргумента:

  • source — одноразовый итератор строк (идентификаторов посылок длиной от 0 до 30 символов; общее количество элементов в источнике от 0 до 512);
  • batch_size — положительное целое число, размер полной партии (от 1 до 64);
  • limit_batches — неотрицательное целое число, максимальное количество выдаваемых полных партий (от 0 до 32).

Функция должна возвращать кортеж вида (batches, tail):

  • batches — одноразовый ленивый итератор, выдающий только полные партии в виде кортежей длины batch_size;
  • tail — изначально пустой изменяемый список (list), куда помещается хвостовой остаток.

Правила обработки потока:

  • В момент самого вызова postal_batches из source не должно считываться ни одного элемента. Все чтения происходят строго лениво по мере запросов из итератора batches.
  • Каждый шаг получения очередной партии извлекает из source не более одного набора элементов, сохраняя исходный порядок следования и возможные дубликаты идентификаторов.
  • Итератор batches выдаёт не более limit_batches полных партий. Как только это количество выдано, обращения к source полностью прекращаются: нельзя делать даже проверочный вызов для проверки конца потока.
  • Если лимит limit_batches равен 0, функция не считывает из источника ни одного значения, итератор batches завершается сразу, а tail остаётся пустым.
  • Если поток естественным образом исчерпался (StopIteration) до набора лимита limit_batches и последняя сформированная пачка оказалась неполной (её размер больше 0, но меньше batch_size), эти элементы добавляются в список tail по месту (tail.extend(...)), а сам генератор batches завершает работу и не выдаёт эту неполную пачку.
  • Если лимит партий достигнут либо поток исчерпался точно на границе полной партии (неполного остатка нет), список tail остаётся пустым.
  • Список tail заполняется только в процессе обхода batches; предварительно извлекать остаток при создании кортежа запрещено.

Ввод и вывод

Стандартные потоки stdin и stdout не используются. Проверяющая система импортирует и вызывает функцию верхнего уровня postal_batches напрямую из пространства имён модуля после выполнения кода студента.

Пример использования

source = make_postal_source(['a', 'b', 'c', 'd', 'e'])
batches, tail = postal_batches(source, 2, 3)
print(list(batches))
print(tail)
print(observe_postal_source(source)['successful_reads'])

Вывод:

[('a', 'b'), ('c', 'd')]
['e']
5
РешениеPython

Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.

Отправьте решение, чтобы увидеть результаты тестов.

Связанные задачи