交替发电机

时间:2015-04-28 23:06:32

标签: python generator yield iterable

我的教授希望我们编写一个以* args为参数的生成器,并产生第一个参数的第一个值,然后是第二个的第一个值,然后是第三个的第一个值。当它完成时,它产生第一个的第二个值,第二个的第二个值,等等。

我在迭代迭代时遇到了一些麻烦,因为它们的长度不同。因此,虽然一个iterable可能长度为4,另一个可能长度为2,因此尝试生成两者的第3个值会导致错误。

我希望生成器在它运行到一个已经用完迭代结束值的参数时停止。

编辑:这是我到目前为止......

temp = list(args)
while True:
    for x in range(len(temp)):
        for letters in args:
            yield next(letters)

现在它给了我一个类型错误:'str'对象不是迭代器当我尝试运行这行时...

[print(i) for i in alternate('abcde', 'fg', 'hijk')]

我不允许使用 zip 或任何其他导入。

该函数可以接受字符串和iterables作为参数

6 个答案:

答案 0 :(得分:1)

您可以使用itertoolsizipchain的组合:

from itertools import izip, chain

def foo(*iters):
    return chain.from_iterable(izip(*iters))

for bar in foo([1, 2], [3, 4, 5], [6, 7]):
    print bar

结果:

1
3
6
2
4
7

在此示例中,izip(*iters)将返回生成:

的迭代器
(1, 3, 6)
(2, 4, 7)

由于5在单个迭代器耗尽时停止,因此不会生成值izipchain.from_iterable会将每个元组视为数字的迭代器,并将所有这些值链接在一起。

修改

由于不允许zip,我们可以根据itertools页面提供的代码提供我们自己的实现:

def foo(*iters):
    iterators = map(iter, iters)
    while iterators:
        for v in map(next, iterators):
            yield v

答案 1 :(得分:1)

我最终解决了这个问题(不使用拉链,因为我不允许)。

temp = [iter(arg) for arg in args]
while True:
    for x in range(len(temp)):
        for letters in temp:
            yield next(letters)

我使用list comprehension创建所有参数的列表,同时将所有参数附加为iterables。之后,我只是使用while循环来重复迭代列表中的每个值,直到我用完迭代。一旦它检测到没有更多要迭代,它就会突破循环。

答案 2 :(得分:0)

使用zip()

>>> def mygen(*args):
...     for i in zip(*args):
...             for j in i:
...                     yield j
...
>>> a = mygen('abcde', 'fg', 'hijk')
>>> next(a)
'a'
>>> next(a)
'f'
>>> next(a)
'h'
>>> next(a)
'b'
>>> next(a)
'g'
>>> next(a)
'i'
>>> next(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

答案 3 :(得分:0)

这是一个递归解决方案

def myGen(x):
   for i in x:
       if len(i) < 1:
          break
       yield i[0]
   else:
      for j in myGen([z[1:] for z in x]):
          yield j

答案 4 :(得分:0)

def alternate(*args):
    shortest = min(map(len, args))
    for i in xrange(shortest):
        for arg in args:
            yield arg[i]

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

输出:

a
f
h
b
g
i

答案 5 :(得分:0)

Xari,你真的不需要外部for循环,例如for x in range(len(temp)):

def alternate2(*args):
    if len(args) == 0:
        return
    temp = [iter(arg) for arg in args]
    while True:
        for letters in temp:
            yield next(letters)