sourcetip

python에서 목록이 항목을 공유하는지 테스트합니다.

fileupload 2023. 5. 23. 22:19
반응형

python에서 목록이 항목을 공유하는지 테스트합니다.

한 목록에 있는 항목이 다른 목록에 있는지 확인하고 싶습니다.아래의 코드로 간단하게 할 수 있지만, 이를 위한 라이브러리 기능이 있을 것 같습니다.그렇지 않다면, 같은 결과를 얻을 수 있는 더 피톤적인 방법이 있을까요?

In [78]: a = [1, 2, 3, 4, 5]

In [79]: b = [8, 7, 6]

In [80]: c = [8, 7, 6, 5]

In [81]: def lists_overlap(a, b):
   ....:     for i in a:
   ....:         if i in b:
   ....:             return True
   ....:     return False
   ....: 

In [82]: lists_overlap(a, b)
Out[82]: False

In [83]: lists_overlap(a, c)
Out[83]: True

In [84]: def lists_overlap2(a, b):
   ....:     return len(set(a).intersection(set(b))) > 0
   ....: 

단답: 사용not set(a).isdisjoint(b)일반적으로 가장 빠릅니다.

두 개의 리스트가 있는지 테스트하는 네 가지 일반적인 방법이 있습니다.a그리고.b모든 항목을 공유합니다.은 둘 다 를 들어 다음과 같습니다.

bool(set(a) & set(b))

집합은 Python에서 해시 테이블을 사용하여 저장되기 때문에 검색은 다음과 같습니다(Python에서 연산자의 복잡성에 대한 자세한 내용은 여기를 참조하십시오).이론적으로 이것은O(n+m)에 있어서 평균적으로n그리고.ma그리고.b.그렇지만

  1. 먼저 목록에서 집합을 만들어야 하며, 이는 취소할 수 없는 시간이 걸릴 수 있습니다.
  2. 해싱 충돌이 데이터 사이에서 드문 것으로 가정합니다.

두 번째 방법은 다음과 같이 목록에서 반복을 수행하는 생성기 식을 사용하는 것은 다음과 같습니다.

any(i in a for i in b)

이렇게 하면 내부 검색이 가능하므로 중간 변수에 새 메모리가 할당되지 않습니다.그것은 또한 첫 번째 발견에도 도움이 됩니다.그러나 연산자는 항상 목록에 있습니다(여기 참조).

제안된 또 다른 옵션은 목록 중 하나를 반복하고, 집합에서 다른 하나를 변환하고, 다음과 같이 이 집합에서 구성원 자격을 테스트하는 하이브리드입니다.

a = set(a); any(i in a for i in b)

네 번째 접근 방식은 다음과 같은 이점을 활용하는 것입니다.isdisjoint()예를 들어, 다음과 같은 (아래 참조) 집합의 방법입니다.

not set(a).isdisjoint(b)

검색하는 요소가 배열의 시작 근처에 있는 경우(예: 정렬됨), 집합 교차 방법은 중간 변수에 대해 새 메모리를 할당해야 하므로 생성기 식을 사용하는 것이 좋습니다.

from timeit import timeit
>>> timeit('bool(set(a) & set(b))', setup="a=list(range(1000));b=list(range(1000))", number=100000)
26.077727576019242
>>> timeit('any(i in a for i in b)', setup="a=list(range(1000));b=list(range(1000))", number=100000)
0.16220548999262974

다음은 목록 크기 함수에 대한 이 예제의 실행 시간 그래프입니다.

시작할 때 공유하는 경우 요소 공유 테스트 실행 시간

두 축 모두 로그입니다.이것은 생성기 식에 대한 최상의 사례를 나타냅니다. 보피시다,피시▁the▁as,isdisjoint()방법은 목록 크기가 매우 작은 경우에 더 나은 반면 생성기 식은 목록 크기가 큰 경우에 더 좋습니다.

반면에 하이브리드 및 생성기 식에 대한 검색이 시작될 때 공유 요소가 배열의 끝에 체계적으로 있는 경우(또는 두 목록 모두 값을 공유하지 않는 경우) 분리 및 설정 교차 접근 방식이 생성기 식 및 혼합 접근 방식보다 훨씬 빠릅니다.

>>> timeit('any(i in a for i in b)', setup="a=list(range(1000));b=[x+998 for x in range(999,0,-1)]", number=1000))
13.739536046981812
>>> timeit('bool(set(a) & set(b))', setup="a=list(range(1000));b=[x+998 for x in range(999,0,-1)]", number=1000))
0.08102107048034668

요소 공유 종료 시 테스트 실행 시간 공유

목록 크기가 클수록 생성기 식이 훨씬 느립니다.이는 이전 그림의 100000이 아니라 1000번의 반복에만 해당됩니다.또한 이 설정은 요소가 공유되지 않을 때 근사하며, 분리 및 설정 교차로 접근에 가장 적합한 경우입니다.

다음은 (설정을 한 가지 또는 다른 기법에 맞게 조정하는 대신) 난수를 사용한 두 가지 분석입니다.

공유 가능성이 높은 랜덤 생성 데이터에 대한 요소 공유 테스트 실행 시간 공유 가능성이 높은 랜덤 생성 데이터에 대한 요소 공유 테스트 실행 시간

공유 가능성이 높음: 요소가 무작위로 추출됨[1, 2*len(a)]공유 가능성이 낮음: 임의로 요소를 추출합니다.[1, 1000*len(a)].

지금까지 이 분석에서는 두 목록의 크기가 동일하다고 가정했습니다.예를 들어 크기가 다른 두 리스트의 경우a더 작습니다.isdisjoint()항상 더 빠름:

처음에 공유할 때 크기가 다른 두 개의 목록에서 테스트 실행 시간을 공유하는 요소 마지막에 공유할 때 크기가 다른 두 개의 목록에서 테스트 실행 시간을 공유하는 요소

다음을 확인합니다.a저하됩니다.list는 하가저성됩능니다이록수작을▁list다. 이실에서는,a하게 되었습니다.5.

요약:

  • 작은 의 원소), 리트가매작경우은(10개의 원소),not set(a).isdisjoint(b)항상 가장 빠릅니다.
  • 수 있는 인 구조를 표현식은 과 .any(i in a for i in b)크기에서 .
  • 을 설된교 테트합 다니스를로 합니다.not set(a).isdisjoint(b)그것은 항상 보다 빠릅니다.bool(set(a) & set(b)).
  • " 하이목리 "록에서반복드테스, 서에트세트브"▁the"a = set(a); any(i in a for i in b)일반적으로 다른 방법보다 느립니다.
  • 생성기 식과 하이브리드는 요소를 공유하지 않는 목록에 대해 다른 두 가지 접근 방식보다 훨씬 느립니다.

대부분의 경우 다음을 사용합니다.isdisjoint()되지 않을 때 식을 실행하는 데 더 에 가장 입니다.

def lists_overlap3(a, b):
    return bool(set(a) & set(b))

참고: 위에서는 부울을 답으로 사용할 것으로 가정합니다.에 .if문, 문, 냥사용을 합니다.if set(a) & set(b):

def lists_overlap(a, b):
  sb = set(b)
  return any(el in sb for el in a)

O(이며, 보다 더 수 .any의 짧은 설명입니다.

예:

lists_overlap([3,4,5], [1,2,3])

하를대로 True 다합니환반는달다에 합니다.3 in sb

편집: 또 다른 변형 (Dave Kirby 덕분):

def lists_overlap(a, b):
  sb = set(b)
  return any(itertools.imap(sb.__contains__, a))

이는 다음에 의존합니다.imap생성기 이해가 아닌 C로 구현되는 반복기.또한 다음을 사용합니다.sb.__contains__매핑 함수로 사용됩니다.저는 이것이 얼마나 많은 성능 차이를 만드는지 모릅니다.계속 단락됩니다.

은 또한 수있다습니도를 사용할 .any목록 이해력 포함:

any([item in a for item in b])

python 2.6 이상에서는 다음을 수행할 수 있습니다.

return not frozenset(a).isdisjoint(frozenset(b))

any builted function /wa 제너레이터 식을 사용할 수 있습니다.

def list_overlap(a,b): 
     return any(i for i in a if i in b)

John과 Lie가 지적했듯이 두 목록에서 공유하는 모든 i에 대해 bool(i) == False가 잘못된 결과를 제공합니다.다음과 같아야 합니다.

return any(i in b for i in a)

이 질문은 꽤 오래된 것이지만, 저는 사람들이 세트와 리스트를 논쟁하는 동안 아무도 그것들을 함께 사용할 생각을 하지 않았다는 것을 알아차렸습니다.소라ux의 예를 따라,

목록에 대한 최악의 경우:

>>> timeit('bool(set(a) & set(b))',  setup="a=list(range(10000)); b=[x+9999 for x in range(10000)]", number=100000)
100.91506409645081
>>> timeit('any(i in a for i in b)', setup="a=list(range(10000)); b=[x+9999 for x in range(10000)]", number=100000)
19.746716022491455
>>> timeit('any(i in a for i in b)', setup="a= set(range(10000)); b=[x+9999 for x in range(10000)]", number=100000)
0.092626094818115234

그리고 목록에 대한 최상의 사례:

>>> timeit('bool(set(a) & set(b))',  setup="a=list(range(10000)); b=list(range(10000))", number=100000)
154.69790101051331
>>> timeit('any(i in a for i in b)', setup="a=list(range(10000)); b=list(range(10000))", number=100000)
0.082653045654296875
>>> timeit('any(i in a for i in b)', setup="a= set(range(10000)); b=list(range(10000))", number=100000)
0.08434605598449707

따라서 두 개의 목록을 반복하는 것보다 더 빠른 속도로 목록이 집합에 있는지 확인하는 것이 반복되는데, 이는 숫자가 집합에 있는지 확인하는 것은 일정한 시간이 걸리고 목록을 반복하여 확인하는 것은 목록의 길이에 비례하는 시간이 걸리기 때문입니다.

따라서 제 결론은 목록을 반복해서 한 세트로 되어 있는지 확인하는 것입니다.

중복되는 요소가 무엇이든 상관없다면 간단히 확인할 수 있습니다.len조합된 목록 대 조합된 목록의 비율입니다.겹치는 요소가 있으면 집합이 더 짧아집니다.

len(set(a+b+c))==len(a+b+c)중복이 없는 경우 True를 반환합니다.

저는 기능적인 프로그래밍 스타일로 다른 것을 넣을 것입니다.

any(map(lambda x: x in a, b))

설명:

map(lambda x: x in a, b)

다음 요소가 있는 부울 목록을 반환합니다.b에서 찾을 수 있습니다.a그런 다음 해당 목록이 다음으로 전달됩니다.any그것은 간단히 되돌아옵니다.True 요소가 떤요있가다면소인 경우True.

언급URL : https://stackoverflow.com/questions/3170055/test-if-lists-share-any-items-in-python

반응형