Как сделать выборку из Iterable генераторов в Python 3? - PullRequest
0 голосов
/ 05 сентября 2018

Учитывая list из generator значений:

from itertools import repeat

ones_gen = repeat(1)

twos_gen = repeat(2)

threes_gen = repeat(3)

gen_list = [ones_gen, twos_gen, threes_gen]

Как мне создать еще один генератор, который будет производить выборку из списка для чередования значений базовых исходных генераторов?

Новый генератор должен выдать 1 2 3 1 2 3 1 2 3....

Примечание: это тривиальный пример, который можно воспроизвести с помощью cycle([1,2,3]), но только пример.

Заранее благодарим вас за внимание и ответ.

Ответы [ 2 ]

0 голосов
/ 05 сентября 2018

Если все ваши генераторы имеют одинаковую длину (включая бесконечную), вы можете связать вместе значения, сгенерированные с помощью zip():

from itertools import chain

chain.from_iterable(zip(*gen_list))

Если длины могут отличаться, и израсходованные генераторы следует выбросить, используйте пример roundrobin() из документации itertools :

from itertools import cycle, islice

def roundrobin(*iterables):
    "roundrobin('ABC', 'D', 'EF') --> A D E B F C"
    # Recipe credited to George Sakkis
    num_active = len(iterables)
    nexts = cycle(iter(it).__next__ for it in iterables)
    while num_active:
        try:
            for next in nexts:
                yield next()
        except StopIteration:
            # Remove the iterator we just exhausted from the cycle.
            num_active -= 1
            nexts = cycle(islice(nexts, num_active))

Демо из последних:

>>> from itertools import repeat, islice
>>> ones_gen = repeat(1)
>>> twos_gen = repeat(2)
>>> limited_threes_gen = islice(repeat(3), 2)  # just two values
>>> rrgen = roundrobin(ones_gen, twos_gen, limited_threes_gen)
>>> next(rrgen)
1
>>> next(rrgen)
2
>>> next(rrgen)
3
>>> next(rrgen)
1
>>> next(rrgen)
2
>>> next(rrgen)
3
>>> next(rrgen)
1
>>> next(rrgen)
2
>>> next(rrgen)
1

Тройки закончились, но два других генератора продолжают работать.

0 голосов
/ 05 сентября 2018

Использование chain.from_iterable с zip

>>> cc = chain.from_iterable(zip(*gen_list))
>>> next(cc)
1
>>> next(cc)
2
>>> next(cc)
3
>>> next(cc)
1
>>> next(cc)
2
>>> next(cc)
3

Если генераторы не бесконечны и имеют разную длину, вы можете вместо этого использовать стратегию циклического перебора. В рецептах itertools есть пример .

...