在迭代中产生替代值

时间:2015-04-27 10:48:07

标签: python python-3.x

我得到了许多迭代,我需要在第一个iterable中生成所有值,然后在第二个中生成所有值,...,最后一个iterable中的所有值。

示例

for i in alternate('abcde','fg','hijk'): 
      print(i,end=' ')

预计会产生值

a f h b g i c

我知道按顺序打印所有字符,如

'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'

以下是代码:

def alternate(*args):
    for iterable in args:
        for item in iterable:
            yield item

但是如何让它们交替出现呢?

2 个答案:

答案 0 :(得分:5)

如果您想在最短列表中终止,请使用zip

  

创建一个聚合来自每个迭代的元素的迭代器。

def alternate(*args):
    # note: python 2 - use izip_longest
    for iterable in zip(*args):
        for item in iterable:
            if item is not None:
                yield item

如果您想使用所有项目,请使用itertools.izip_longest

  

创建一个聚合来自每个迭代的元素的迭代器。如果迭代的长度不均匀,则使用fillvalue填充缺失值。

def alternate(*args):
    # note: python 2 - use izip_longest
    for iterable in itertools.zip_longest(*args):
        for item in iterable:
            if item is not None:
                yield item

请注意,它会跳过None个值(可以使用fillvalue更改)。

没有itertools

def alternate(*args):
    max_len = max(map(len, args))
    for index in range(max_len):
        for lst in args:
            try:
                yield lst[index]
            except IndexError:
                continue

停止第一个“缺失”项目:

def alternate(*args):
    index = 0
    while True:
        for lst in args:
            try:
                yield lst[index]
            except IndexError:
                return
        index += 1

如果您正在使用生成器(或迭代器),当其中一个完成时,您将获得StopIteration,因此您可以使用iter创建一般函数:

def alternate(*args):
    iters = [iter(lst) for lst in args]
    while True:
        for itr in iters:
            try:
                yield next(itr)
            except StopIteration:
                return

答案 1 :(得分:0)

这将做你想要的。它适用于任何输入,如果其中一个项目为None,则不会绊倒。它使用内置的itertools模块,只能使用内置的python模块在python 3.x和python 2.7上运行。它基于Python itertools文档中的roundrobin函数:

from itertools import cycle

def roundrobin_shortest(*iterables):
    "roundrobin_shortest('ABCD', 'EF', 'GHI') --> A E G B F H C"
    nexts = cycle(iter(it).__next__ for it in iterables)
    while True:
        try:
            for inext in nexts:
                yield inext()
        except StopIteration:
            break

此版本的工作原理基本相同,但有点短:

from itertools import chain, cycle

def roundrobin_shortest(*iterables):
    "roundrobin_shortest('ABCD', 'EF', 'GHI') --> A E G B F H C"
    nexts = cycle(iter(it).__next__ for it in iterables)
    yield from chain.from_iterable(inext() for inext in nexts)

没有itertools的版本:

def roundrobin_shortest(*iterables):
    "roundrobin_shortest('ABCD', 'EF', 'GHI') --> A E G B F H C"
    items = [iter(item) for item in iterables]
    while True:
       try:
           for it in items:
               yield next(it)
       except StopIteration:
           break

你可以使用以下任何一种:

>>> for i in roundrobin_shortest('abcde','fg','hijk'): 
...     print(i, end=' ')
...
a f h b g i c 

或者这是一个更简单的单行

>>> from itertools import chain, cycle
>>> iters = ('abcde','fg','hijk')
>>> res = chain.from_iterable(j() for j in cycle(iter(j).__next__ for j in iters))
>>> print(' '.join(res))
a f h b g i c