python-izip循环遍历所有的iterable,直到最长的完成

2024-09-28 13:25:53 发布

您现在位置:Python中文网/ 问答频道 /正文

这对我来说不是一件小事,而且我找不到任何收据,所以也许你可以给我指一张,或者你有一个现成的、适当的、经过调整的解决方案?正确含义也适用于不知道自身长度的迭代器(没有__len__),也适用于可穷尽迭代器(例如链式迭代器);经过良好调整的含义很快。在

注意:就地解决方案是不可能的,因为需要缓存迭代器的输出来重新迭代它们(Glenn Maynard指出了这一点)。在

用法示例:

>>> list(izip_cycle(range(2), range(5), range(3)))
[(0, 0, 0), (1, 1, 1), (0, 2, 2), (1, 3, 0), (0, 4, 1)]
>>> from itertools import islice, cycle, chain
>>> list(islice(izip_cycle(cycle(range(1)), chain(range(1), range(2))), 6))
[(0, 0), (0, 0), (0, 1), (0, 0), (0, 0), (0, 1)]

Tags: chainlen方案range解决方案list链式收据
3条回答

这里有一些灵感来自itertools.teeitertools.cycle。它适用于任何类型的iterable:

class izip_cycle(object):
    def __init__(self, *iterables ):
        self.remains = len(iterables)
        self.items = izip(*[self._gen(it) for it in iterables])

    def __iter__(self):
        return self.items

    def _gen(self, src):
        q = []
        for item in src:
            yield item
            q.append(item)

        # done with this src
        self.remains -=1
        # if there are any other sources then cycle this one
        # the last souce remaining stops here and thus stops the izip
        if self.remains:
            while True:
                for item in q:
                    yield item
def izip_cycle_inplace(*iterables):
    def wrap(it):
        empty = True
        for x in it: empty = yield x
        if empty: return
        next(counter)
        while True:
            empty = True
            for x in it: empty = yield x
            if empty: raise ValueError('cannot cycle iterator in-place')
    iterators = [wrap(i) for i in iterables]
    counter = iter(iterators)
    next(counter)
    while True:
        yield [next(i) for i in iterators]

def izip_cycle(*iterables):
    def wrap(it):
        elements = []
        for x in it:
            yield x
            elements.append(x)
        if not elements: return
        next(counter)
        while True:
            for x in elements: yield x
    iterators = [wrap(i) for i in iterables]
    counter = iter(iterators)
    next(counter)
    while True:
        yield [next(i) for i in iterators]

根据您的要求,一种可能对您有用的简单方法是:

import itertools

def izip_cycle(*colls):
    maxlen = max(len(c) if hasattr(c,'__len__') else 0 for c in colls)
    g = itertools.izip(*[itertools.cycle(c) for c in colls])

    for _ in range(maxlen):
        yield g.next()

第一件事就是找出最长序列的长度,这样它就知道要重复多少次。没有__len__的序列被计算为长度为0;这可能是你想要的——如果你有一个没有结束的序列,你可能想在有限序列上重复。虽然这不能处理没有长度的有限迭代器。在

我们永远不会使用^{}创建每个迭代器的循环版本,然后使用^{}将它们压缩在一起。在

最后,我们从zip中生成每个条目,直到给出所需数量的结果。在

如果您想让这对没有len的有限迭代器有效,我们需要自己做更多的工作:

^{pr2}$

这基本上是Python implementation of ^{} in the documentation的扩展,可以在多个序列上运行。我们保存在saved中看到的项目来重复并跟踪exhausted中哪些序列用完了。在

因为这个版本会等待所有序列的运行,如果你传入无限的东西,循环将永远运行下去。在

相关问题 更多 >

    热门问题