多くの場合、リストをペアで処理する必要があることがわかりました。私はそれを行うためのpythonicかつ効率的な方法はどれだろうと思っていました、そしてこれをGoogleで見つけました:
pairs = zip(t[::2], t[1::2])
私はそれは十分にパイソンだと思ったが、イディオム対効率に関する最近の議論の後で、私はいくつかのテストをすることに決めた:
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
これらは私のコンピュータ上の結果でした:
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でのリスト、リストのインデックス付け、リストのスライスの実装が非常に効率的であることを意味するはずです。それは慰めと予想外の両方の結果です。
リストをペアでトラバースする別の「より良い」方法はありますか?
リストの要素数が奇数の場合、最後の要素はどのペアにも含まれないことに注意してください。
すべての要素が含まれていることを確認するための正しい方法はどれですか?
テストへの回答から次の2つの提案を追加しました。
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
これまでの結果
最もpythonicで非常に効率的:
pairs = izip(t[::2], t[1::2])
最も効率的で非常にpythonic:
pairs = izip(*[iter(t)]*2)
最初の答えが2つのイテレータを使用しているのに対して、2番目のイテレータは1つのイテレータを使用しているのを見るのに少し時間がかかりました。
奇数の要素を持つシーケンスを処理するためにNone
、以前の最後の要素とペアになる1つの要素()を追加する元のシーケンスを拡張するという提案がありましたitertools.izip_longest()
。これはで実現できます。
最後に
Python 3.xでは、zip()
として動作しitertools.izip()
、itertools.izip()
なくなっていることに注意してください。
timeit
モジュールの代わりにいくつかのmumbo-jumboを使用しているため。