web-dev-qa-db-ja.com

単一リストからのペア

多くの場合、リストをペアで処理する必要があることがわかりました。私はそれを行うためのPythonの効率的な方法はどれだろうと思っていましたが、Googleでこれを見つけました:

_pairs = Zip(t[::2], t[1::2])
_

Pythonicで十分だと思いましたが、最近の イディオムと効率 を含む議論の後、いくつかのテストを行うことにしました:

_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つのイテレータを使用することを理解するのに少し時間がかかりました。

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

最後に

Python 3.x、Zip()itertools.izip()として動作し、itertools.izip()はなくなりました。

83
Apalala

私のお気に入りの方法:

from itertools import izip

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

# for "pairs" of any length
def chunkwise(t, size=2):
    it = iter(t)
    return izip(*[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)
41
Jochen Ritzel

最初の解pairs = Zip(t[::2], t[1::2])が一番読みやすいと思います(そしてPython 3、Zipは自動的にイテレータを返しますリストの代わりに)。

すべての要素が含まれていることを確認するには、Noneでリストを単純に拡張できます。

次に、リストに奇数の要素がある場合、最後のペアは(item, None)

>>> t = [1,2,3,4,5]
>>> t.append(None)
>>> Zip(t[::2], t[1::2])
[(1, 2), (3, 4), (5, None)]
>>> t = [1,2,3,4,5,6]
>>> t.append(None)
>>> Zip(t[::2], t[1::2])
[(1, 2), (3, 4), (5, 6)]
36
Tim Pietzcker

私は小さな免責事項から始めます-以下のコードを使用しないでください。まったくPythonicではありません。ただ楽しみのために書きました。 @ THC4k pairwise関数に似ていますが、iterおよびlambdaクロージャーを使用します。 itertoolsモジュールを使用せず、fillvalueをサポートしません。誰かがそれを面白いと思うかもしれないので、私はここにそれを置きます:

pairwise = lambda t: iter((lambda f: lambda: (f(), f()))(iter(t).next), None)
6
Tomasz Elendt

ほとんどのPythonicに関する限り、 python source docs)で提供されるレシピ (@JochenRitzelが提供した回答によく似ているものもあります)おそらくあなたの最善の策です;)

def grouper(iterable, n, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx
    args = [iter(iterable)] * n
    return izip_longest(fillvalue=fillvalue, *args)
3
Pat

リストをペアでたどる別の「より良い」方法はありますか?

確かに言うことはできませんが、私はそれを疑います:他のトラバーサルには、さらに多くのPythonコードを解釈する必要があります。Zip()などの組み込み関数は、はるかに高速。

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

リストの長さを確認し、奇数の場合(len(list) & 1 == 1)、リストをコピーしてアイテムを追加します。

2
Aaron Digulla
>>> my_list = [1,2,3,4,5,6,7,8,9,10]
>>> my_pairs = list()
>>> while(my_list):
...     a = my_list.pop(0); b = my_list.pop(0)
...     my_pairs.append((a,b))
... 
>>> print(my_pairs)
[(1, 2), (3, 4), (5, 6), (7, 8), (9, 10)]
0