Jak sprawdzić, czy wszystkie poniższe pozycje znajdują się na liście?

114

Stwierdziłem, że jest powiązane pytanie, jak sprawdzić, czy na liście znajduje się co najmniej jeden element:
Jak sprawdzić, czy jeden z poniższych elementów znajduje się na liście?

Ale jaki jest najlepszy i pytoniczny sposób sprawdzenia, czy wszystkie elementy znajdują się na liście?

Przeszukując dokumenty znalazłem to rozwiązanie:

>>> l = ['a', 'b', 'c']
>>> set(['a', 'b']) <= set(l)
True
>>> set(['a', 'x']) <= set(l)
False

Inne rozwiązanie byłoby takie:

>>> l = ['a', 'b', 'c']
>>> all(x in l for x in ['a', 'b'])
True
>>> all(x in l for x in ['a', 'x'])
False

Ale tutaj musisz pisać więcej.

Czy są jakieś inne rozwiązania?

sirex
źródło
5
Co jest nie tak set(smaller) <= set(larger)?
eumiro
1
Myślę, że twoje drugie rozwiązanie z „wszystkim” wygląda dla mnie dobrze i pytonicznie.
Jiho Noh

Odpowiedzi:

157

Operatory takie jak <=w Pythonie generalnie nie są nadpisywane, aby oznaczać coś znacznie innego niż „mniejsze lub równe”. To niezwykłe, że standardowa biblioteka to robi - dla mnie pachnie jak starsze API.

Użyj odpowiednika i sposób bardziej wyraźnie nazwane set.issubset. Zauważ, że nie musisz konwertować argumentu na zbiór; w razie potrzeby zrobi to za Ciebie.

set(['a', 'b']).issubset(['a', 'b', 'c'])
Glenn Maynard
źródło
2
nie wiedziałem, że możesz przekazać listę bezpośrednio jako argument do issubset ... nice!
tsimbalar
1
Chociaż zgadzam się z tym sentymentem, jestem całkiem w porządku, jeśli chodzi o pomysł <=i issubsetznaczenie tego samego. Dlaczego tego nie lubisz?
Kirk Strauser,
2
@Just: Przede wszystkim dlatego, że nie jest oczywiste, co <=oznacza zbiór bez szukania go w dokumentacji lub posiadania wcześniejszej wiedzy o tym, co to znaczy w teorii mnogości, podczas gdy każdy wie, co to issubsetznaczy automatycznie.
Glenn Maynard
2
Znasz operator matematyczny dla (niewłaściwego) podzbioru? w zasadzie wygląda jak zaokrąglony <=;)
dom0
uwielbiam to rozwiązanie. czy istnieje sposób na uzyskanie lokalizacji indeksu lub wartości listy zamiast wartości bool (True: False)?
Vlad Gulin,
62

Prawdopodobnie użyłbym setw następujący sposób:

set(l).issuperset(set(['a','b'])) 

lub odwrotnie:

set(['a','b']).issubset(set(l)) 

Uważam, że jest trochę bardziej czytelny, ale może być przesadzony. Zestawy są szczególnie przydatne do obliczania sumy / przecięć / różnic między kolekcjami, ale może nie być najlepszą opcją w tej sytuacji ...

tsimbalar
źródło
Właściwie MySet.issubset(MyOtherSet)i MySet <= MyOtherSetsą takie same.
Wok
1
@wok: och, nie wiedziałem tego, ale myślę, że składnia <= jest nieco zagmatwana, ponieważ podobnej składni można używać z listami, ale o bardzo innym znaczeniu.
tsimbalar
3
to naprawdę nie jest takie mylące, jeśli przypomnisz sobie, że włączenie definiuje częściową kolejność w dowolnym zbiorze zbiorów. Właściwie jest to nieco zagmatwane, że <=ma znaczenie, jakie ma dla sekwencji: można by się spodziewać, że oznacza „jest podciągiem”, a nie porządkiem leksykograficznym.
aaronasterling
1
@aaronasterling: mmm, osobiście nie myślę zbyt wiele o "częściowym zamówieniu", kiedy piszę kod :-), ale zgadzam się z tym, że używanie <=z sekwencjami również wydaje się dziwne, jakoś ...
tsimbalar
3
Pobiegłem do małego Gotcha tutaj chciałbym wspomnieć: W przypadku korzystania z tej metody, konwersja list do zbiorów, co oznacza, że nie ma duplikatów. set(['a','a']).issubset(['a'])zwraca True.
Orangestar
11

Podoba mi się te dwa, ponieważ wydają się najbardziej logiczne, te drugie są krótsze i prawdopodobnie najszybsze (pokazane tutaj przy użyciu setskładni literalnej, która została przeniesiona do Pythona 2.7):

all(x in {'a', 'b', 'c'} for x in ['a', 'b'])
#   or
{'a', 'b'}.issubset({'a', 'b', 'c'})
martineau
źródło
Rozwiązanie „wszystko” jest najszybsze, gdy mierzysz je za pomocą metody timeit (). To powinna być akceptowana odpowiedź.
Attersson,
3

Co się stanie, jeśli Twoje listy zawierają takie duplikaty:

v1 = ['s', 'h', 'e', 'e', 'p']
v2 = ['s', 's', 'h']

Zestawy nie zawierają duplikatów. Tak więc następujący wiersz zwraca True.

set(v2).issubset(v1)

Aby liczyć na duplikaty, możesz użyć kodu:

v1 = sorted(v1)
v2 = sorted(v2)


def is_subseq(v2, v1):
    """Check whether v2 is a subsequence of v1."""
    it = iter(v1)
    return all(c in it for c in v2) 

Tak więc następujący wiersz zwraca False.

is_subseq(v2, v1)
Maks
źródło
1

To właśnie szukałem w Internecie, ale niestety nie znalazłem go w Internecie, ale podczas eksperymentów z interpretera Pythona.

>>> case  = "caseCamel"
>>> label = "Case Camel"
>>> list  = ["apple", "banana"]
>>>
>>> (case or label) in list
False
>>> list = ["apple", "caseCamel"]
>>> (case or label) in list
True
>>> (case and label) in list
False
>>> list = ["case", "caseCamel", "Case Camel"]
>>> (case and label) in list
True
>>>

a jeśli masz dłuuugą listę zmiennych przechowywanych w pliku sublist variable

>>>
>>> list  = ["case", "caseCamel", "Case Camel"]
>>> label = "Case Camel"
>>> case  = "caseCamel"
>>>
>>> sublist = ["unique banana", "very unique banana"]
>>>
>>> # example for if any (at least one) item contained in superset (or statement)
...
>>> next((True for item in sublist if next((True for x in list if x == item), False)), False)
False
>>>
>>> sublist[0] = label
>>>
>>> next((True for item in sublist if next((True for x in list if x == item), False)), False)
True
>>>
>>> # example for whether a subset (all items) contained in superset (and statement)
...
>>> # a bit of demorgan's law
...
>>> next((False for item in sublist if item not in list), True)
False
>>>
>>> sublist[1] = case
>>>
>>> next((False for item in sublist if item not in list), True)
True
>>>
>>> next((True for item in sublist if next((True for x in list if x == item), False)), False)
True
>>>
>>>
Emirhan Özlen
źródło
0

Przykładem tego, jak to zrobić za pomocą wyrażenia lambda, byłoby:

issublist = lambda x, y: 0 in [_ in x for _ in y]
Jundullah
źródło
1
Dodaj komentarze, aby wyjaśnić / rozwinąć swoją odpowiedź
Sharad
0

Nie w przypadku OP, ale - dla każdego, kto chce potwierdzić przecięcie w dyktach i wylądował tutaj z powodu słabego wyszukiwania w Google (np. Ja) - musisz popracować z dict.items:

>>> a = {'key': 'value'}
>>> b = {'key': 'value', 'extra_key': 'extra_value'}
>>> all(item in a.items() for item in b.items())
True
>>> all(item in b.items() for item in a.items())
False

Dzieje się tak, ponieważ dict.itemszwraca krotki par klucz / wartość i podobnie jak każdy obiekt w Pythonie, są one zamiennie porównywalne

Julio Cezar Silva
źródło