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?


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'])

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 ...


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'})

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)

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
>>>
>>>

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]

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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.