Рубрики
Без рубрики

Решение: хлопотный итератор, загадка Python

Это подробное решение этой загадки. Вот снова: напишите функцию (куски), где я … Теги с Python.

Это подробное решение этой загадки.

Вот еще раз: написать функцию ( Куски ), где вход – итератор. И выход – итератор 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)}')

Выход:

A  type 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

Выход:

A  type 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”