여러 세트의 교차점을 찾는 가장 좋은 방법은 무엇입니까?


266

세트 목록이 있습니다.

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

s1 ∩ s2 ∩ s3을 원합니다 ...

일련의 pairwise s1.intersection(s2)등 을 수행하여 함수를 작성할 수 있습니다 .

권장되거나, 더 좋거나 내장 된 방법이 있습니까?

답변:


454

Python 버전 2.6부터 다음 set.intersection()과 같이 여러 인수를 사용할 수 있습니다.

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

세트가 목록에 있으면 다음과 같이 해석됩니다.

u = set.intersection(*setlist)

목록 확장*a_list 은 어디에 있습니까

참고 set.intersection입니다 하지 정적 메서드하지만,이 목록의 나머지 부분과 첫 번째 집합의 교집합을 적용하기 위해 기능 표기법을 사용합니다. 따라서 인수 목록이 비어 있으면 실패합니다.


65

2.6 set.intersection부터는 반복적으로 많은 iterable이 필요합니다.

>>> 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])

24

분명히 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}

12

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])

그러나 Guido 자신을 포함하여 많은 Python 프로그래머가 싫어합니다 .

약 12 년 전, 파이썬은 람다, reduce (), filter () 및 map ()을 인수했습니다. 그러나 PR 값에도 불구하고 이러한 기능은 Python 3000에서 잘라야한다고 생각합니다.

이제 reduce (). 이것은 실제로 항상 가장 싫어하는 것입니다. + 또는 *와 관련된 몇 가지 예제 외에도 거의 사소한 함수 인수로 reduce () 호출을 볼 때마다 펜과 종이를 가져와야하기 때문에 reduce ()가 무엇을해야하는지 이해하기 전에 실제로 그 함수에 무엇이 공급되는지 다이어그램으로 나타내십시오. 내 마음에, reduce ()의 적용 가능성은 연관 연산자로 거의 제한되어 있으며 다른 모든 경우에는 누적 루프를 명시 적으로 작성하는 것이 좋습니다.


8
Guido는 사용 reduce이 "연관 연산자로 제한됩니다" 라고 말하며이 경우에 적용 할 수 있습니다. reduce파악하기가 매우 어렵지만 &그렇게 나쁘지는 않습니다.
Mike Graham


reduce와 관련된 유용한 최적화에 대해서는 python.org/doc/essays/list2str 을 확인하십시오 . 그것은 일반 빌드 목록, 세트, 문자열 등의 가치에 아주 능숙하게 사용할 수있는 모습도 github.com/EntilZha/PyFunctional
안드레아스

result비어 있을 때 루프를 끊으면 최적화 할 수 있습니다.
bfontaine

1

다음은 사용 가능한 최상의 방법을 활용하기 위해 다중 세트 교차에 대한 일반 기능을 제공합니다.

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있지만, 나는 그것을 좋아합니다. :)


sets에 액세스 sets[0]하여 잡는 대신 길이를 확인해야 합니다 IndexError.
bfontaine

이것은 평범한 점검이 아닙니다. a_set최종 반환에 사용됩니다.
tzot

당신은 할 수 return reduce(sets[0], sets[1:]) if sets else set()없습니까?
bfontaine

네, 감사합니다. 가능하면 try/에 의존 except하지 않도록 코드를 변경 해야합니다. 코드 냄새, 비효율적이며 다른 문제를 숨길 수 있습니다.
bfontaine

0

장 프랑수아 파 브레 (Jean-François Fabre) set.intesection (* list_of_sets) 답변은 분명히 가장 Pyhtonic이며 정답입니다.

reduce를 사용하려는 사람들에게는 다음도 작동합니다.

reduce(set.intersection, list_of_sets)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.