Чередование между итераторами в Python [дубликат]

Этот вопрос уже имеет ответ здесь:

Что является самым эффективным способом чередовать принимающие значения от различных итераторов в Python, так, чтобы, например, alternate(xrange(1, 7, 2), xrange(2, 8, 2)) уступил бы 1, 2, 3, 4, 5, 6. Я знаю, что один способ реализовать его был бы:

def alternate(*iters):
    while True:
        for i in iters:
            try:
                yield i.next()
            except StopIteration:
                pass

Но есть ли более эффективный или более чистый путь? (Или, еще лучше, itertools функционируйте я отсутствовал?)

9
задан LeafStorm 7 January 2010 в 02:46
поделиться

5 ответов

как насчет zip? вы также можете попробовать izip из itertools

>>> zip(xrange(1, 7, 2),xrange(2, 8 , 2))
[(1, 2), (3, 4), (5, 6)]

, если это не то, что вы хотите, пожалуйста, приведите больше примеров в вашем вопросе.

7
ответ дан 4 December 2019 в 06:41
поделиться

Для "чистой" реализации вы хотите

itertools.chain(*itertools.izip(*iters))

, но, возможно, вы хотите

itertools.chain(*itertools.izip_longest(*iters))
17
ответ дан 4 December 2019 в 06:41
поделиться

Если они одинаковой длины, itertools.izip можно использовать следующим образом:

def alternate(*iters):
    for row in itertools.izip(*iters):
       for i in row:
           yield i
1
ответ дан 4 December 2019 в 06:41
поделиться

См. roundrobin в разделе itertools "Recipes". Это более общая версия альтернативы.

def roundrobin(*iterables):
    "roundrobin('ABC', 'D', 'EF') --> A D E B F C"
    # Recipe credited to George Sakkis
    pending = len(iterables)
    nexts = cycle(iter(it).__next__ for it in iterables)
    while pending:
        try:
            for next in nexts:
                yield next()
        except StopIteration:
            pending -= 1
            nexts = cycle(islice(nexts, pending))
6
ответ дан 4 December 2019 в 06:41
поделиться

Можно определить alternate следующим образом:

import itertools
def alternate(*iters):   
    for elt in itertools.chain.from_iterable(
        itertools.izip(*iters)):
        yield elt

print list(alternate(xrange(1, 7, 2), xrange(2, 8, 2)))

Это оставляет открытым вопрос о том, что делать, если один итератор остановится раньше другого. Если вы хотите продолжить до тех пор, пока не исчерпается самый длинный итератор, то можно использовать itertools.izip_longest вместо itertools.izip.

import itertools
def alternate(*iters):   
    for elt in itertools.chain.from_iterable(
        itertools.izip_longest(*iters)):
        yield elt
print list(alternate(xrange(1, 7, 2), xrange(2, 10, 2)))

Это поставит урожайность

[1, 2, 3, 4, 5, 6, None, 8]

Примечание Нет урожайности, когда xrange итератора(1,7,2) поднимает StopIteration (не имеет больше элементов).

Если бы вы хотели просто пропустить итератор вместо того, чтобы выдавать None, вы могли бы сделать это:

Dummy=object()

def alternate(*iters):   
    for elt in itertools.chain.from_iterable(
        itertools.izip_longest(*iters,fillvalue=Dummy)):
        if elt is not Dummy:
            yield elt
2
ответ дан 4 December 2019 в 06:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: