您的输出似乎受到第一个迭代器it1 的输出的限制。所以我们可以按原样使用it1,并用无限的None-yielding 迭代器和zip 填充it2。
>>> from itertools import repeat,izip,chain
>>> somezip = lambda it1,it2: izip(it1,chain(it2,repeat(None)))
>>> list(somezip(a,b))
[(1, 5), (2, 6), (3, 7), (4, 8)]
>>> list(somezip(a,c))
[(1, 10), (2, 11), (3, 12), (4, None)]
repeat(None) 创建迭代器,无限生成None。
chain 粘合 it2 和 repeat(None)。
izip 将在it1 用完后立即停止生成。
其他解决方案有一些缺陷(我在 cmets 中留下了评论)。它们可能运行良好,但有一些输入可能会意外失败。
正如 glglgl 在 cmets 中建议的那样,此函数宁愿接受参数中可变数量的迭代器。
所以我更新了代码来工作:
from itertools import repeat,izip,chain,imap
somezip = lambda it1,*its: izip(it1,*imap(chain,its,repeat(repeat(None))))
测试:
>>> print(list(somezip(a,b)))
print(list(somezip(a,c)))
print(list(somezip(b,a,c)))
[(1, 5), (2, 6), (3, 7), (4, 8)]
[(1, 10), (2, 11), (3, 12), (4, None)]
[(5, 1, 10), (6, 2, 11), (7, 3, 12), (8, 4, None), (9, None, None)]
我不得不在这里使用imap,尽管没有必要这样做(因为参数稍后会被解包,所以简单的map 就可以了)。原因是mapdon't accept iterators of different length,而imap在消耗最小迭代器时停止。
所以,imap 将chain 应用于除第一个迭代器和chains 之外的所有迭代器,每个迭代器都使用repeat(None)。为了服务its 的每个迭代器,我在repeat(None) 上方使用了另一个repeat(注意,这在其他项目中可能非常危险,因为外部repeat 产生的所有对象都是同一个对象repeat(None),所以最后他们所有的chained 迭代器共享它)。然后我解压缩imap 对象以生成izip 的参数,它返回值直到it1 被消耗(因为chained its 现在每个都生成无限的值序列)。
请注意,所有操作都在纯 C 中工作,因此不涉及解释器开销。
为了阐明它的工作原理,我添加了以下详细说明:
def somezip(it1,*its): #from 0 to infinite iterators its
# it1 -> a1,a2,a3,...,an
# its -> (b1,b2,b3,...,bn),(c1,c2,c3,...,cn),...
infinite_None = repeat(None) # None,None,None,...
infinite_Nones = repeat(infinite_None) # infinite_None,infinite_None,... (share the same infinite_None)
chained = imap(chain,its,infinite_Nones) # [(b1,b2,b3,...,bn,None,None,...),(c1,c2,c3,...,cn,None,None,...),...]
return izip(it1,*chained)
单线就是:
somezip = lambda it1,*its: izip(it1,*imap(chain,its,repeat(repeat(None))))