可变长度'收益率'?

时间:2012-10-22 18:13:28

标签: python generator enumerate

我希望能够yield一个可变数量的项目,这些项目将允许编写类似于以下内容的生成器函数:

x = [1, 2, 3]
y = [4, 5, 6]
z = [7, 8, 9]

def multi_enumerate(*iterables):
    n = 0
    iterators = map(iter, iterables)
    while iterators:
        yield n, *tuple(map(next, iterators))  # invalid syntax
        n += 1

for i,a,b,c in multi_enumerate(x, y, z):
    print i,a,b,c

有人知道某种方法吗?我知道我可以产生一个元组,但这需要在接收端显式解压缩,例如:a,b,c = t[0], t[1], t[2]

最终解决方案

FWIW,这是我最终使用的内容,基于John Kugelman的出色答案:

from itertools import izip

def multi_enumerate(*iterables, **kwds):
    start = kwds.get('start')
    if start is None:
        if kwds: raise TypeError(
            "multi_enumerate() accepts only the keyword argument 'start'")
        try:
            iter(iterables[-1])  # last non-keyword arg something iterable?
        except TypeError:        # no, assume it's the start value
            start, iterables = iterables[-1], iterables[:-1]
        else:
            start = 0  # default

    return ((n,)+t for n, t in enumerate(izip(*iterables), start))

添加的代码是因为我希望它也接受一个可选的非可迭代的最后一个参数来指定一个非0的起始值(或使用start关键字参数指定它),就像构建的一样-in enumerate()功能。

4 个答案:

答案 0 :(得分:5)

yield语句更改为:

yield (n,) + tuple(map(next, iterators))

或者使用izipenumerate来消除整个循环:

from itertools import izip

def multi_enumerate(*iterables):
    return ((n,) + t for n, t in enumerate(izip(*iterables)))

答案 1 :(得分:1)

我会使用chain中的itertools

yield tuple(chain((n,), map(next, iterators)))

答案 2 :(得分:0)

这将返回一个迭代器,为(n, *l[n]) i生成n - 长度l s。它将直接代替您的multienumerate方法。

from itertools import izip
def enumerated_columns(*rows):
    return izip(range(len(rows[0])), *rows)

答案 3 :(得分:0)

如果你想将生成器中的几个项目委托到其他生成器,那么除非你使用Python features yield from

我会迭代嵌套的生成器,显式地从它们中产生值,比如

yield n
for value in (delegated.next for delegated in iterators):
  yield value