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
그리고.m
의 a
그리고.b
.그렇지만
- 먼저 목록에서 집합을 만들어야 하며, 이는 취소할 수 없는 시간이 걸릴 수 있습니다.
- 해싱 충돌이 데이터 사이에서 드문 것으로 가정합니다.
두 번째 방법은 다음과 같이 목록에서 반복을 수행하는 생성기 식을 사용하는 것은 다음과 같습니다.
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
'sourcetip' 카테고리의 다른 글
이미지 URL을 system.drawing.image로 변환하려면 어떻게 해야 합니까? (0) | 2023.05.23 |
---|---|
쉬운 인터뷰 질문이 어려워졌습니다: 1번이 주어졌습니다.100, 정확하게 k가 누락된 경우 결측 번호 찾기 (0) | 2023.05.23 |
ElementName 바인딩에 실패했습니다. (0) | 2023.05.23 |
목록(String) 또는 배열 또는 배열 목록 (0) | 2023.05.23 |
노드JS: base64 인코딩된 문자열을 다시 이진으로 디코딩하는 방법은 무엇입니까? (0) | 2023.05.18 |