Python有内置函数用于混合生成器/序列吗?
我注意到,itertools
似乎没有一个可以将多个可迭代对象的元素交错排列的函数(也就是和合并不同)。
def leaf(*args): return (it.next() for it in cycle(imap(chain,args)))
tuple(leaf(['Johann', 'Sebastian', 'Bach'], repeat(' '))) => ('Johann', ' ', 'Sebastian', ' ', 'Bach', ' ')
(编辑)我之所以这么问,是因为我想避免不必要的合并和扁平化操作。
显然,leaf
的定义很简单,但如果有一个预定义的函数可以做到同样的事情,我更愿意使用那个,或者是一个非常清晰的生成器表达式。 在 itertools 或其他一些知名库中,有这样的内置函数吗,或者有什么合适的表达方式?
编辑 2:使用 functional
包,可以得到一个更简洁的定义:
from itertools import *
from functional import *
compose_mult = partial(reduce, compose)
leaf = compose_mult((partial(imap, next), cycle, partial(imap, chain), lambda *args: args))
3 个回答
2
这个自定义函数会把多个迭代器交替组合在一起,并一直进行,直到所有的迭代器都用完为止。
def interleave_iterators(*iterators):
finished = [False for x in range(len(iterators))]
stop_cond = functools.reduce(lambda x,y:not x or not y,finished)
while stop_cond:
for i,it in enumerate(iterators):
try:
yield next(it)
except StopIteration:
finished[i] = True
stop_cond = functools.reduce(lambda x,y:not x or not y,finished)
比如说
it1 = iter([2,4,6,8])
it2 = iter([1,3,5,7,9,11,13])
for x in interleave_iterators(it1,it2): # prints 2 1 4 3 6 5 8 7 9 11 13
print(str(x),end=" ")
17
你可以使用内置的 zip
和 itertools.chain.from_iterable
来把结果变得更简单易读:
>>> import itertools
>>> list(zip(['Johann', 'Sebastian', 'Bach'], itertools.repeat(' ')))
[('Johann', ' '), ('Sebastian', ' '), ('Bach', ' ')]
>>> list(itertools.chain.from_iterable(_))
['Johann', ' ', 'Sebastian', ' ', 'Bach', ' ']
注意,我使用 list
只是为了让输出看起来更好。使用标准的 itertools,leaf
的其他实现方式可以是:
leaf = lambda *a: itertools.chain.from_iterable(itertools.izip(*a)) # Python 2.x
leaf = lambda *a: itertools.chain.from_iterable(zip(*a)) # Python 3.x
8
itertools库里的roundrobin()方法本来是我最想用的,不过在你这个具体的例子里,它会产生一个无限的序列,因为它是根据最长的可迭代对象来停止,而不是最短的。当然,这个问题很容易解决。也许换个思路看看这个方法会更好?