web-dev-qa-db-ja.com

複数のセットの交差点を見つける最良の方法は?

セットのリストがあります:

setlist = [s1,s2,s3...]

私はs1∩s2∩s3が欲しい...

一連のペアワイズs1.intersection(s2)などを実行することで、それを行う関数を作成できます。

推奨、改善、または組み込みの方法はありますか?

212
user116293

Pythonバージョン2.6以降では、 set.intersection() に複数の引数を使用できます。

u = set.intersection(s1, s2, s3)

セットがリストにある場合、これは次のように変換されます。

u = set.intersection(*setlist)

ここで*a_listリスト展開 です

374
sth

2.6の時点で、set.intersectionは任意の数の反復可能オブジェクトを取ります。

>>> s1 = set([1, 2, 3])
>>> s2 = set([2, 3, 4])
>>> s3 = set([2, 4, 6])
>>> s1 & s2 & s3
set([2])
>>> s1.intersection(s2, s3)
set([2])
>>> sets = [s1, s2, s3]
>>> set.intersection(*sets)
set([2])
61
Mike Graham

明らかにset.intersectionがここで必要なものですが、「これらすべての合計を取る」、「これらすべての製品を取る」、「これらすべてのxorを取る」という一般化が必要な場合は、探しているものはreduce関数:

from operator import and_
from functools import reduce
print(reduce(and_, [{1,2,3},{2,3,4},{3,4,5}])) # = {3}

または

print(reduce((lambda x,y: x&y), [{1,2,3},{2,3,4},{3,4,5}])) # = {3}
17
Thomas Ahle

Python 2.6以降をお持ちでない場合は、代わりに明示的なforループを記述します。

def set_list_intersection(set_list):
  if not set_list:
    return set()
  result = set_list[0]
  for s in set_list[1:]:
    result &= s
  return result

set_list = [set([1, 2]), set([1, 3]), set([1, 4])]
print set_list_intersection(set_list)
# Output: set([1])

reduceを使用することもできます。

set_list = [set([1, 2]), set([1, 3]), set([1, 4])]
print reduce(lambda s1, s2: s1 & s2, set_list)
# Output: set([1])

しかし、多くのPythonプログラマーはそれを嫌います Guido自身を含む

約12年前、Pythonはラムダ、reduce()、filter()、map()を取得しました。それらを逃し、動作中のパッチを提出したLISPハッカーのおかげです(私は信じています)。しかし、PR値にもかかわらず、これらの機能はPython 3000からカットされるべきだと思います。

だから今reduce()。これは、実際に私が常に最も嫌っていたものです。なぜなら、+または*を含むいくつかの例は別として、非自明な関数引数を持つreduce()呼び出しを見るたびに、ペンと紙をつかむ必要があるからです。 reduce()が何をすべきかを理解する前に、実際にその関数に何が送られているかを図で示します。したがって、私の考えでは、reduce()の適用可能性は連想演算子にほぼ限定されており、他のすべての場合では、累積ループを明示的に書き出す方が適切です。

11
Ayman Hourieh

ここでは、利用可能な最善の方法を活用しようとする複数集合交差の汎用関数を提供しています。

def multiple_set_intersection(*sets):
    """Return multiple set intersection."""
    try:
        return set.intersection(*sets)
    except TypeError: # this is Python < 2.6 or no arguments
        pass

    try: a_set= sets[0]
    except IndexError: # no arguments
        return set() # return empty set

    return reduce(a_set.intersection, sets[1:])

Guidoはreduceを嫌うかもしれませんが、私はそれが好きです:)

1
tzot