2010-09-23 54 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