it-source

목록에서 여러 값의 구성원을 테스트하는 방법

criticalcode 2023. 6. 15. 21:55
반응형

목록에서 여러 값의 구성원을 테스트하는 방법

두 개 이상의 값이 목록에 구성원 자격이 있는지 테스트하려고 하는데 예기치 않은 결과가 나타납니다.

>>> 'a','b' in ['b', 'a', 'foo', 'bar']
('a', True)

그렇다면 파이썬은 목록에서 여러 값의 멤버십을 동시에 테스트할 수 있습니까?그 결과는 무엇을 의미합니까?


참고 항목:목록 교차점을 어떻게 찾습니까?지정된 값이 리스트에 있는지 확인하는 것은 교차점이 비어 있지 않은지 확인하는 것과 같습니다.모든 값이 목록에 있는지 확인하는 것은 값이 부분 집합인지 확인하는 것과 같습니다.

이는 사용자가 원하는 것을 수행하며, 거의 모든 경우에 작동합니다.

>>> all(x in ['b', 'a', 'foo', 'bar'] for x in ['a', 'b'])
True

그 표현은'a','b' in ['b', 'a', 'foo', 'bar']Python이 튜플로 해석하기 때문에 예상대로 작동하지 않습니다.

>>> 'a', 'b'
('a', 'b')
>>> 'a', 5 + 2
('a', 7)
>>> 'a', 'x' in 'xerxes'
('a', True)

기타 옵션

이 테스트를 실행할 수 있는 다른 방법이 있지만 다양한 종류의 입력에 대해 작동하지 않습니다.카비가 지적했듯이, 당신은 세트를 사용하여 이 문제를 해결할 수 있습니다...

>>> set(['a', 'b']).issubset(set(['a', 'b', 'foo', 'bar']))
True
>>> {'a', 'b'} <= {'a', 'b', 'foo', 'bar'}
True

...가끔:

>>> {'a', ['b']} <= {'a', ['b'], 'foo', 'bar'}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

집합은 해시 가능한 요소로만 만들 수 있습니다.하지만 발전기 표현은all(x in container for x in items)에서는 거의 모든 컨테이너 유형을 처리할 수 있습니다.유일한 요구 사항은container반복할 수 있습니다(즉, 발전기가 아님). items가히 가증스러울 수도 있습니다.

>>> container = [['b'], 'a', 'foo', 'bar']
>>> items = (i for i in ('a', ['b']))
>>> all(x in [['b'], 'a', 'foo', 'bar'] for x in items)
True

속도 테스트

대부분의 경우 부분 집합 검정이 다음보다 빠릅니다.all그러나 세트가 선택사항이 아니기 때문에 질문이 관련이 없는 경우를 제외하고는 그 차이는 충격적이지 않습니다.이와 같은 테스트 목적으로만 목록을 세트로 변환하는 것은 항상 문제를 해결할 가치가 없습니다.그리고 발전기를 세트로 변환하는 것은 때때로 엄청나게 낭비적일 수 있으며, 프로그램의 속도를 엄청나게 늦출 수 있습니다.

다음은 몇 가지 예시 벤치마크입니다.가장 큰 차이는 두 가지 경우에 발생합니다.container그리고.items상대적으로 작습니다.이 경우, 부분 집합 접근 방식이 약 몇 배 더 빠릅니다.

>>> smallset = set(range(10))
>>> smallsubset = set(range(5))
>>> %timeit smallset >= smallsubset
110 ns ± 0.702 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
>>> %timeit all(x in smallset for x in smallsubset)
951 ns ± 11.5 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

이것은 큰 차이처럼 보입니다.하지만, 만약에 한...container세트입니다.all훨씬 더 큰 규모에서도 여전히 완벽하게 사용할 수 있습니다.

>>> bigset = set(range(100000))
>>> bigsubset = set(range(50000))
>>> %timeit bigset >= bigsubset
1.14 ms ± 13.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
>>> %timeit all(x in bigset for x in bigsubset)
5.96 ms ± 37 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

부분 집합 테스트를 사용하는 것이 여전히 더 빠르지만, 이 규모에서는 약 5배 정도밖에 되지 않습니다.속도 향상은 Python의 빠른 속도 덕분입니다.c지원되는 구현set하지만 기본 알고리즘은 두 경우 모두 동일합니다.

만약 당신이items다른 이유로 이미 목록에 저장된 경우에는 부분 집합 검정 접근 방식을 사용하기 전에 이를 집합으로 변환해야 합니다.그러면 속도가 약 2.5배로 떨어집니다.

>>> %timeit bigset >= set(bigsubseq)
2.1 ms ± 49.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

그리고 만약 당신이container는 시퀀스이며, 먼저 변환해야 하며, 그러면 속도가 더 작아집니다.

>>> %timeit set(bigseq) >= set(bigsubseq)
4.36 ms ± 31.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

우리가 비참하게 느린 결과를 얻는 유일한 시간은 우리가 떠날 때입니다.container순서대로:

>>> %timeit all(x in bigseq for x in bigsubseq)
184 ms ± 994 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

그리고 물론, 우리는 필요할 때만 그렇게 할 것입니다. 모든 bigseq해시 가능한 경우 대신 다음 작업을 수행합니다.

>>> %timeit bigset = set(bigseq); all(x in bigset for x in bigsubseq)
7.24 ms ± 78 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

.set(bigseq) >= set(bigsubseq)시간은 4.36초)입니다.

따라서 부분 집합 테스트가 일반적으로 더 빠르지만, 놀라운 차이는 아닙니다.다른 한편으로, 언제가all더 빠릅니다.면 어쩌지items천만 개의 가치가 길고, 존재하지 않는 가치를 가질 가능성이 높습니다.container?

>>> %timeit hugeiter = (x * 10 for bss in [bigsubseq] * 2000 for x in bss); set(bigset) >= set(hugeiter)
13.1 s ± 167 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>>> %timeit hugeiter = (x * 10 for bss in [bigsubseq] * 2000 for x in bss); all(x in bigset for x in hugeiter)
2.33 ms ± 65.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

이 경우 발전기를 세트로 변환하는 것은 엄청나게 낭비적인 것으로 밝혀졌습니다.set생성자는 전체 생성자를 사용해야 합니다.하지만 단락된 행동은all제너레이터의 일부만 소비하면 되므로 서브셋 테스트보다 크기가 4배 더 빠릅니다.

이것은 인정하건대 극단적인 예입니다.그러나 이와 같이 어느 한 쪽의 접근 방식이 모든 경우에 더 빠를 것이라고 가정할 수는 없습니다.

업샷

대부분의 경우, 변환 중container적어도 모든 요소가 해시 가능한 경우 세트에 대한 가치가 있습니다.ㅠㅠㅠin1)이고, 반면에 경우인면 O(1)반세의,in시퀀스는 O(n)입니다.

반면에, 부분 집합 테스트를 사용하는 것은 아마도 가끔만 가치가 있을 것입니다.테스트 항목이 이미 세트에 저장되어 있는 경우에는 반드시 이 작업을 수행합니다.않으면, 않면으지그.all속도가 조금 느릴 뿐이며 추가 스토리지가 필요하지 않습니다.또한 대규모 항목 생성기와 함께 사용할 수 있으며, 이러한 경우에는 엄청난 속도 향상을 제공하기도 합니다.

다른 방법:

>>> set(['a','b']).issubset( ['b','a','foo','bar'] )
True

입력된 일치 항목을 모두 확인하려면,

>>> all(x in ['b', 'a', 'foo', 'bar'] for x in ['a', 'b'])

하나 이상의 일치 항목을 확인하려면,

>>> any(x in ['b', 'a', 'foo', 'bar'] for x in ['a', 'b'])

난 거의 확신해.in는 보다 순우 높다습니가보다 우선 .,은 그서당신진술로 되고 있습니다.'a', ('b' in ['b' ...])그리고 나서 그것은 평가됩니다.'a', True 이래'b'배열에 있습니다.

원하는 작업을 수행하는 방법은 이전 답변을 참조하십시오.

Python 파서는 그 진술을 튜플로 평가했고, 여기서 첫 번째 값은'a'그리고 두 번째 값은 표현식입니다.'b' in ['b', 'a', 'foo', 'bar']는 (으)로 합니다.True).

원하는 작업을 수행하는 간단한 기능을 작성할 수 있습니다.

def all_in(candidates, sequence):
    for element in candidates:
        if element not in sequence:
            return False
    return True

그리고 다음과 같이 부릅니다.

>>> all_in(('a', 'b'), ['b', 'a', 'foo', 'bar'])
True
[x for x in ['a','b'] if x in ['b', 'a', 'foo', 'bar']]

제가 이것이 선택된 답보다 더 좋다고 생각하는 이유는 'all()' 함수를 부를 필요가 없기 때문입니다.IF 문에서 빈 목록은 False로 평가되고 비어 있지 않은 목록은 True로 평가됩니다.

if [x for x in ['a','b'] if x in ['b', 'a', 'foo', 'bar']]:
    ...Do something...

예:

>>> [x for x in ['a','b'] if x in ['b', 'a', 'foo', 'bar']]
['a', 'b']
>>> [x for x in ['G','F'] if x in ['b', 'a', 'foo', 'bar']]
[]

저는 우리가 그 대괄호들을 뺄 수도 있다고 말하고 싶습니다.

array = ['b', 'a', 'foo', 'bar']
all([i in array for i in 'a', 'b'])

여기에 제시된 두 답변 모두 반복되는 요소를 처리하지 않습니다.예를 들어 [1,2,2]가 [1,2,3,4]의 하위 목록인지 여부를 테스트하는 경우 둘 다 True를 반환합니다.그게 당신이 하려는 의도일 수도 있지만, 저는 단지 명확히 하고 싶었습니다.[1,2,3,4]의 [1,2,2]에 대해 false를 반환하려면 두 목록을 모두 정렬하고 각 목록에서 이동 인덱스를 사용하여 각 항목을 확인해야 합니다.루프를 위해서는 조금 더 복잡할 뿐입니다.

제가 한 방법은 다음과 같습니다.

A = ['a','b','c']
B = ['c']
logic = [(x in B) for x in A]
if True in logic:
    do something

조금도

를 Python3의 할 수 .any:

>>> {'a','b'} & set(['b', 'a', 'foo', 'bar'])
{'a', 'b'}

>>> {'a','b'} & set(['b', 1, 'foo', 'bar'])
{'b'}

물론 당신은 결과를 위해 부울로 포장할 수 있습니다.True/False값:

>>> bool({'a','b'} & set(['b', 1, 'foo', 'bar']))
True

>>> bool({'c'} & set(['b', 1, 'foo', 'bar']))
False

모든.

is 부분 집합 사용:

>>> {'a','b'}.issubset(set(['b', 'a', 'foo', 'bar']))
True

>>> {'a','b'}.issubset(set(['b', 1, 'foo', 'bar']))
False

메모들

  • bool() 로설정으로 됩니다.
  • issubset()이 될 .
  • &에 할 수 .

다음 변수를 사용하여 예제를 정리할 수 있습니다.

test = {'a','b'}
values = set(['b', 'a', 'foo', 'bar'])

# Any
test & values         # {'a', 'b'}
bool(test & values)   # True

# All
test.issubset(values) # True

람다 없이 어떻게 비단결처럼 될 수 있습니까!심각하게 받아들일 필요는 없지만 이 방법도 효과가 있습니다.

orig_array = [ ..... ]
test_array = [ ... ]

filter(lambda x:x in test_array, orig_array) == test_array

배열에 값이 있는지 테스트하려면 끝 부분을 생략합니다.

filter(lambda x:x in test_array, orig_array)
# This is to extract all count of all combinations inside list of 
# list
import itertools

l = [[1,2,3],[6,5,4,3,7,2],[4,3,2,9],[6,7],[5,1,0],[6,3,2,7]]    
els = list(set(b for a in l for b in a))    
sol = {}    

def valid(p):    
    for s in l:    
        if set(p).issubset(set(s)):    
            if p in sol.keys():    
                sol[p] += 1    
            else:    
                sol[p] = 1    

for c in itertools.combinations(els, 2):    
    valid(c)  
# {(0, 1): 1, 
# (0, 5): 1,
# (1, 2): 1,
# (1, 3): 1,
# (1, 5): 1,
# (2, 3): 4,
# (2, 4): 2,
# (2, 5): 1,
# (2, 6): 2,
# (2, 7): 2,
# (2, 9): 1,
# (3, 4): 2,
# (3, 5): 1,
# (3, 6): 2,
# (3, 7): 2,
# (3, 9): 1,
# (4, 5): 1,
# (4, 6): 1,
# (4, 7): 1,
# (4, 9): 1,
# (5, 6): 1,
# (5, 7): 1,
# (6, 7): 3}   

언급URL : https://stackoverflow.com/questions/6159313/how-to-test-the-membership-of-multiple-values-in-a-list

반응형