Это подробное решение этой загадки.
Вот еще раз: написать функцию ( Куски
), где вход – итератор. И выход – итератор n
Размер итераторы.
Первая задача состоит в том, что длина оригинального итератора неизвестна. Давайте начнем с наивного сломанного решения, используя Itertools.islice
создать n
Размер итераторы без заботы о продолжительности оригинального итератора:
import itertools from typing import TypeVar, Iterator T = TypeVar('T') def chunks(iterator: Iterator[T], n: int) -> Iterator[Iterator[T]]: while True: yield itertools.islice(iterator, 0, n) # yield `n` size chunk of the iterator for chunk in chunks(iter(range(10)), 3): print(f'A {type(chunk)} type chunk, contains items: {tuple(chunk)}')
Выход:
Atype chunk, contains items: (0, 1, 2) A type chunk, contains items: (3, 4, 5) A type chunk, contains items: (6, 7, 8) A type chunk, contains items: (9,) A type chunk, contains items: () A type chunk, contains items: () .... forever
Использование Itertools.islice
Нам удалось курить оригинальный итератор, но мы не знаем, когда оно истощено. И так, куски
это генераторная функция, которая никогда не заканчивается.
Чтобы преодолеть эту проблему, нам нужно взять один товар из оригинального итератора. Тогда мы будем использовать Itertools.Chain
Чтобы создать кусок с участием этого предмета и N-1
Больше предметов.
def chunks(iterator: Iterator[T], n: int) -> Iterator[Iterator[T]]: for first in iterator: # take one item out (exits loop if `iterator` is empty) rest_of_chunk = itertools.islice(iterator, 0, n - 1) yield itertools.chain([first], rest_of_chunk) # concatenate the first item back
Выход:
Atype chunk, contains items: (0, 1, 2) A type chunk, contains items: (3, 4, 5) A type chunk, contains items: (6, 7, 8) A type chunk, contains items: (9,)
И это так!
И в форме понимания (я обычно предпочитаю похватки, но я должен признать, что этот не так читабелен, как форма петли):
return (itertools.chain([first], itertools.islice(iterator, 0, n - 1)) for first in iterator)
Спектакль
Время выполнения islice
-в и цепь
-Ном намного меньше, чем написать свой собственный пользовательский код для куски
Поскольку оба эти функции реализованы в C
(для Cpython
Runtime).
Оговорка
Здесь есть предостережение: все это решение предполагает, что потребитель куски
потребляет итераторы полностью и в порядке. Если это не так, порядок предметов в наших кусках может не соответствовать оригинальному итератору из-за лени куски
.
Пример:
chunk_iterator = chunks(iter(range(10)), 3) first_chunk = next(chunk_iterator) second_chunk = next(chunk_iterator) print(tuple(second_chunk)) # (1, 2, 3) print(tuple(first_chunk)) # (0, 4, 5)
Ваше здоровье!
Оригинал: “https://dev.to/orenovadia/solution-chunked-iterator-python-riddle-3ple”