我的教授希望我们编写一个以* 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作为参数
答案 0 :(得分:1)
您可以使用itertools中izip
和chain
的组合:
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
在单个迭代器耗尽时停止,因此不会生成值izip
。 chain.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)
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)