2010-09-23 33 views
1

考虑:多个迭代的周期?

x = ['a','b','c','d','e'] 
y = ['1','2','3'] 

我想迭代产生:

a, 1 
b, 2 
c, 3 
d, 1 
e, 2 
a, 3 
b, 1 

...其中两个iterables循环独立,直到给定数。

Python的循环(可迭代)可以做到这一点w/1迭代。诸如map和itertools.izip_longest之类的函数可以采用函数来处理None,但不提供内置的自动重复。

一个不太狡猾的想法是将每个列表连接到一个可以均匀迭代的特定大小。 (Boooo!)

对此有何建议?提前致谢。

回答

7
import itertools 
x = ['a','b','c','d','e'] 
y = ['1','2','3'] 
for a, b in itertools.izip(itertools.cycle(x), itertools.cycle(y)): 
    print a, b 
+0

简单胜利! – cwall 2010-09-24 17:23:38

10

最简单的方法是在下面的cyclezip1。它对于大多数目的来说足够快。

import itertools 

def cyclezip1(it1, it2, count): 
    pairs = itertools.izip(itertools.cycle(iter1), 
          itertools.cycle(iter2)) 
    return itertools.islice(pairs, 0, count) 

这里是它的另一个实现,大约快两倍,当count大于it1it2最小公倍数显著较大。

import fractions 

def cyclezip2(co1, co2, count): 
    l1 = len(co1) 
    l2 = len(co2) 
    lcm = l1 * l2/float(fractions.gcd(l1, l2)) 
    pairs = itertools.izip(itertools.cycle(co1), 
          itertools.cycle(co2)) 
    pairs = itertools.islice(pairs, 0, lcm) 
    pairs = itertools.cycle(pairs) 
    return itertools.islice(pairs, 0, count) 

在这里,我们采取的事实,即对将他们的第一n其中nlen(it1)len(it2)最不常见的复式后周期。这当然假定iterables是集合,因此要求它们的长度是有意义的。可以做了进一步的优化是 更换线

pairs = itertools.islice(pairs, 0, lcm) 

pairs = list(itertools.islice(pairs, 0, lcm)) 

这是几乎没有显着的改善(在我的测试约2%),几乎没有一致。它也需要更多的内存。如果预先知道it1it2要足够小,以便额外的内存可以忽略不计,那么可以从中挤出额外的性能。

有趣的是,在收集的情况下,显而易见的事情比第一个选项慢四倍。

def cyclezip3(co1, co2, count): 
    l1 = len(co1) 
    l2 = len(co2) 
    return ((co1[i%l1], co2[i%l2]) for i in xrange(count)) 
+0

感谢优秀击穿! – cwall 2010-09-24 17:23:14