很多时候,我发现需要成对地处理一个列表。我想知道哪种方式更简洁、更有效,于是在谷歌上找到了这个:
pairs = zip(t[::2], t[1::2])
我认为这已经足够了,但在最近一次有关 idioms versus efficiency的讨论之后,我决定做一些测试:
import time
from itertools import islice, izip
def pairs_1(t):
return zip(t[::2], t[1::2])
def pairs_2(t):
return izip(t[::2], t[1::2])
def pairs_3(t):
return izip(islice(t,None,None,2), islice(t,1,None,2))
A = range(10000)
B = xrange(len(A))
def pairs_4(t):
# ignore value of t!
t = B
return izip(islice(t,None,None,2), islice(t,1,None,2))
for f in pairs_1, pairs_2, pairs_3, pairs_4:
# time the pairing
s = time.time()
for i in range(1000):
p = f(A)
t1 = time.time() - s
# time using the pairs
s = time.time()
for i in range(1000):
p = f(A)
for a, b in p:
pass
t2 = time.time() - s
print t1, t2, t2-t1
These were the results on my computer:
1.48668909073 2.63187503815 1.14518594742
0.105381965637 1.35109519958 1.24571323395
0.00257992744446 1.46182489395 1.45924496651
0.00251388549805 1.70076990128 1.69825601578
如果我正确地解释了它们,那应该意味着在 Python 中实现列表、列表索引和列表切片是非常有效的。这是一个既令人欣慰又出乎意料的结果。
有没有另一种“更好”的方法来成对遍历列表?
Note that if the list has an odd number of elements then the last one will not be in any of the pairs.
确保所有元素都包含在内的正确方法是什么?
我从测试的答案中添加了以下两条建议:
def pairwise(t):
it = iter(t)
return izip(it, it)
def chunkwise(t, size=2):
it = iter(t)
return izip(*[it]*size)
以下是结果:
0.00159502029419 1.25745987892 1.25586485863
0.00222492218018 1.23795199394 1.23572707176
最简洁,最有效率:
pairs = izip(t[::2], t[1::2])
最有效率,也是最简洁的:
pairs = izip(*[iter(t)]*2)
我花了一点时间才明白,第一个答案使用两个迭代器,而第二个使用一个迭代器。
为了处理具有奇数个元素的序列,建议增加原始序列中的一个元素(None
) ,它与前一个元素配对,这可以通过 itertools.izip_longest()
实现。
Note that, in Python 3.x, zip()
behaves as itertools.izip()
, and itertools.izip()
is gone.