Robi to, co chcesz i zadziała w prawie wszystkich przypadkach:
>>> all(x in ['b', 'a', 'foo', 'bar'] for x in ['a', 'b'])
True
Wyrażenie 'a','b' in ['b', 'a', 'foo', 'bar']
nie działa zgodnie z oczekiwaniami, ponieważ Python interpretuje je jako krotkę:
>>> 'a', 'b'
('a', 'b')
>>> 'a', 5 + 2
('a', 7)
>>> 'a', 'x' in 'xerxes'
('a', True)
Inne opcje
Istnieją inne sposoby wykonania tego testu, ale nie będą one działać dla wielu różnych rodzajów danych wejściowych. Jak wskazuje Kabie , możesz rozwiązać ten problem za pomocą zestawów ...
>>> set(['a', 'b']).issubset(set(['a', 'b', 'foo', 'bar']))
True
>>> {'a', 'b'} <= {'a', 'b', 'foo', 'bar'}
True
...czasami:
>>> {'a', ['b']} <= {'a', ['b'], 'foo', 'bar'}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
Zestawy można tworzyć tylko z elementami, które można mieszać. Ale wyrażenie generatora all(x in container for x in items)
może obsłużyć prawie każdy typ kontenera. Jedynym wymaganiem jest możliwość container
wielokrotnej iteracji (tj. Nie jest to generator). items
może być w ogóle dowolna iterowalna.
>>> container = [['b'], 'a', 'foo', 'bar']
>>> items = (i for i in ('a', ['b']))
>>> all(x in [['b'], 'a', 'foo', 'bar'] for x in items)
True
Testy prędkości
W wielu przypadkach test podzbioru będzie szybszy niż all
, ale różnica nie jest szokująca - z wyjątkiem sytuacji, gdy pytanie jest nieistotne, ponieważ zestawy nie są opcją. Konwertowanie list na zestawy tylko na potrzeby takiego testu nie zawsze będzie warte zachodu. A przekształcanie generatorów w zestawy może czasami być niewiarygodnie marnotrawne, spowalniając programy o wiele rzędów wielkości.
Oto kilka wzorców dla ilustracji. Największą różnicą jest, gdy oba container
i items
są stosunkowo małe. W takim przypadku podejście do podzbioru jest o rząd wielkości szybsze:
>>> 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)
To wygląda na dużą różnicę. Ale tak długo, jak container
jest to zestaw, all
nadal doskonale nadaje się do użytku w znacznie większych skalach:
>>> 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)
Korzystanie z testów podzbioru jest nadal szybsze, ale tylko o około 5x w tej skali. Przyspieszenie prędkości wynika z szybkiej c
implementacji Pythona set
, ale podstawowy algorytm jest taki sam w obu przypadkach.
Jeśli Twoje items
są już przechowywane na liście z innych powodów, będziesz musiał przekonwertować je na zestaw przed użyciem metody testowania podzbioru. Następnie przyspieszenie spada do około 2,5x:
>>> %timeit bigset >= set(bigsubseq)
2.1 ms ± 49.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
A jeśli twoja container
jest sekwencją i musi zostać najpierw przekonwertowana, to przyspieszenie jest jeszcze mniejsze:
>>> %timeit set(bigseq) >= set(bigsubseq)
4.36 ms ± 31.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
Jedyny przypadek, w którym uzyskujemy katastrofalnie powolne wyniki, to sytuacja, gdy wychodzimy container
w sekwencji:
>>> %timeit all(x in bigseq for x in bigsubseq)
184 ms ± 994 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
Oczywiście zrobimy to tylko wtedy, gdy będziemy musieli. Jeśli wszystkie elementy bigseq
można haszować, zamiast tego zrobimy to:
>>> %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)
To tylko 1,66x szybciej niż alternatywa ( set(bigseq) >= set(bigsubseq)
powyżej 4,36).
Tak więc testowanie podzbiorów jest generalnie szybsze, ale nie z niewiarygodnym marginesem. Z drugiej strony spójrzmy, kiedy all
jest szybszy. A jeśli items
ma długość dziesięciu milionów wartości i prawdopodobnie zawiera wartości, których nie ma 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)
Przekształcenie generatora w zestaw okazuje się w tym przypadku niebywale marnotrawne. set
Konstruktor ma zużywają cały generatora. Ale zachowanie zwarciowe all
zapewnia, że tylko niewielka część generatora musi zostać zużyta, więc jest szybsza niż test podzbioru o cztery rzędy wielkości .
Trzeba przyznać, że to skrajny przykład. Ale jak widać, nie można zakładać, że jedno podejście będzie szybsze we wszystkich przypadkach.
Upshot
W większości przypadków konwersja container
do zestawu jest tego warta, przynajmniej jeśli wszystkie jego elementy dają się haszować. Dzieje się tak, ponieważ in
dla zbiorów wynosi O (1), podczas gdy in
dla sekwencji wynosi O (n).
Z drugiej strony, testowanie podzbiorów jest prawdopodobnie tego warte tylko czasami. Zdecydowanie zrób to, jeśli twoje pozycje testowe są już przechowywane w zestawie. W przeciwnym razie all
jest tylko trochę wolniejszy i nie wymaga dodatkowej pamięci. Może być również używany z dużymi generatorami przedmiotów, a czasami zapewnia ogromne przyspieszenie w tym przypadku.
set(['a', 'b']) <= set(['b','a','foo','bar'])
to inny sposób przeliterowania tego samego i wygląda bardziej matematycznie.{'a', 'b'} <= {'b','a','foo','bar'}
Jestem prawie pewien, że
in
ma wyższy priorytet niż,
tak, że twoja instrukcja jest interpretowana jako'a', ('b' in ['b' ...])
, która następnie obliczana jest na,'a', True
ponieważ'b'
jest w tablicy.Zobacz poprzednią odpowiedź, aby dowiedzieć się, jak robić to, co chcesz.
źródło
Jeśli chcesz sprawdzić wszystkie wprowadzone dopasowania ,
jeśli chcesz sprawdzić co najmniej jeden mecz ,
źródło
Analizator składni Pythona ocenił tę instrukcję jako krotkę, gdzie pierwsza wartość była
'a'
, a druga wartość to wyrażenie'b' in ['b', 'a', 'foo', 'bar']
(którego wynikiem jestTrue
).Możesz jednak napisać prostą funkcję i robić to, co chcesz:
I nazwij to tak:
źródło
Powodem, dla którego uważam, że jest to lepsze niż wybrana odpowiedź, jest to, że naprawdę nie musisz wywoływać funkcji „all ()”. Pusta lista ma wartość Fałsz w instrukcjach JEŻELI, a niepusta lista ma wartość Prawda.
Przykład:
źródło
Powiedziałbym, że możemy nawet pominąć te nawiasy kwadratowe.
źródło
Obie przedstawione tutaj odpowiedzi nie będą dotyczyły powtarzających się elementów. Na przykład, jeśli sprawdzasz, czy [1,2,2] jest podlistą o wartości [1,2,3,4], obie zwrócą wartość True. Może to chcesz zrobić, ale chciałem tylko wyjaśnić. Jeśli chcesz zwrócić false dla [1,2,2] w [1,2,3,4], musisz posortować obie listy i sprawdzić każdą pozycję z ruchomym indeksem na każdej liście. Tylko trochę bardziej skomplikowana pętla for.
źródło
jak możesz być pythonem bez lambd! .. nie traktować poważnie .. ale tak też działa:
pomiń część końcową, jeśli chcesz sprawdzić, czy którakolwiek z wartości znajduje się w tablicy:
źródło
filter
jest generator. Musiałbyś to opakować,list
jeśli chcesz faktycznie uzyskać wynik, który możesz przetestować==
w kontekście logicznym lub w kontekście logicznym (aby sprawdzić, czy jest pusty). Korzystanie z listy ze zrozumieniem lub wyrażenie wytwórcaany
luball
jest korzystne.Oto jak to zrobiłem:
źródło