1. ホーム
  2. python

[解決済み] 単一リストからのペア

2022-09-28 20:47:45

質問

しばしば、私はペアでリストを処理する必要があることに気づきました。私はそれを行うために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におけるリスト、リストインデックス、リストスライスの実装は非常に効率的であることを意味するはずです。これは慰めでもあり、予想外でもある結果です。

ペアでリストをトラバースする別の、"better" 方法はありますか?

リストが奇数の要素を持っている場合、最後のものはどのペアにも含まれないことに注意してください。

すべての要素が含まれることを保証する正しい方法はどれでしょうか?

テストの答えから、この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])

最も効率的で、非常にパイソン的です。

pairs = izip(*[iter(t)]*2)

最初の答えが2つのイテレータを使い、2番目の答えが1つのイテレータを使っていることを理解するのに時間がかかりました。

奇数の要素を持つシーケンスを扱うために、元のシーケンスに1つの要素を追加することが提案されています ( None ) を追加し、前の最後の要素と対になるようにすることが提案されています。 itertools.izip_longest() .

最後に

なお、Python 3.xでは zip() のように振る舞います。 itertools.izip() となり itertools.izip() が消えています。

どのように解決するのですか?

私の好きな方法です。

def pairwise(t):
    it = iter(t)
    return zip(it,it)

# for "pairs" of any length
def chunkwise(t, size=2):
    it = iter(t)
    return zip(*[it]*size)

すべての要素をペアにしたい場合、明らかにfillvalueが必要になるかもしれません。

from itertools import izip_longest
def blockwise(t, size=2, fillvalue=None):
    it = iter(t)
    return izip_longest(*[it]*size, fillvalue=fillvalue)

Python3では itertools.izip は単純に zip ... 古い Python で動作させる場合は

from itertools import izip as zip