90

比較したいものの配列/リストがあるとします。私がよく知っている言語では、次のようなことをします

for (int i = 0, i < mylist.size(); i++)
    for (int j = i + 1, j < mylist.size(); j++)
        compare(mylist[i], mylist[j])

これにより、各ペアを 1 回だけ比較することが保証されます。コンテキストによっては、リストに含まれる一連のオブジェクトに対して衝突検出を行っています。衝突が検出されるたびに、衝突を説明する小さな「衝突」オブジェクトがリストに追加され、別のルーチンが各衝突の解決をループします (衝突する 2 つのオブジェクトの性質によって異なります)。明らかに、私は各衝突を 1 回だけ報告したいと考えています。

さて、Python はインデックスをループするよりもイテレータを使用することを好むので、これを行う pythonic の方法は何ですか?

次の(バグのある)コードがありました:

for this in mylist:
    for that in mylist:
        compare(this, that)

しかし、これは明らかに各衝突を 2 回検出するため、衝突を解決しようとすると奇妙な動作が発生します。では、ここでのPythonicソリューションは何ですか?

4

4 に答える 4

165

もちろん、これにより、各forループがリストのすべての項目を通過するため、各ペアが 2 回生成されます。

ここでitertoolsマジックを使用して、可能なすべての組み合わせを生成できます。

import itertools
for a, b in itertools.combinations(mylist, 2):
    compare(a, b)

itertools.combinationsiterable 内の各要素を他の各要素とペアにしますが、1 回だけです。


forネストされたループを使用して、これまでと同じように、インデックスベースの項目アクセスを使用してこれを記述することもできます。

for i in range(len(mylist)):
    for j in range(i + 1, len(mylist)):
        compare(mylist[i], mylist[j])

もちろん、これは見栄えも Pythonic にも似ていないかもしれませんが、これが最も簡単でわかりやすい解決策であることもあるため、そのような問題を解決することをためらうべきではありません。

于 2013-05-17T07:06:33.563 に答える
30

使用するitertools.combinations(mylist, 2)

mylist = range(5)
for x,y in itertools.combinations(mylist, 2):
    print x,y

0 1
0 2
0 3
0 4
1 2
1 3
1 4
2 3
2 4
3 4
于 2013-05-17T07:05:57.730 に答える