Python: Zobacz, czy jeden zestaw zawiera całkowicie inny?


86

Czy istnieje szybki sposób sprawdzenia, czy jeden zestaw zawiera w całości inny?

Coś jak:

>>>[1, 2, 3].containsAll([2, 1])
True

>>>[1, 2, 3].containsAll([3, 5, 9])
False

Odpowiedzi:


131

To są listy, ale jeśli naprawdę masz na myśli zestawy, możesz użyć metody issubset.

>>> s = set([1,2,3])
>>> t = set([1,2])
>>> t.issubset(s)
True
>>> s.issuperset(t)
True

W przypadku listy nie będziesz w stanie zrobić nic lepszego niż sprawdzenie każdego elementu.


3
Dostaję dziwne uczucie dejavu, gdy widzę tę odpowiedź
Christophe Roussy

musisz zdawać sobie sprawę z semantyki issubset()nie jestcontains()
wikier

37

Dla kompletności: jest to równoważne z issubset(chociaż prawdopodobnie nieco mniej wyraźne / czytelne):

>>> set([1,2,3]) >= set([2,1])
True
>>> set([1,2,3]) >= set([3,5,9])
False

Problem jest taki, że a = zestaw ([]) i b = zestaw (['a', 'b']) to a.issubset (b) jest True
darkman

4

Jedna opcja pozostaje nietknięta - odejmowanie:

>>> {1, 2} - {1, 2, 3}
set([])
>>> {1, 2, 3} - {1, 2}
set([3])

Zasadniczo sprawdzasz, których elementów na pierwszej liście nie ma na drugiej liście.

Uznałem to za bardzo przydatne, ponieważ możesz pokazać, jakich wartości brakuje:

>>> def check_contains(a, b):
...     diff = a - b
...     if not diff:
...         # All elements from a are present in b
...         return True
...     print('Some elements are missing: {}'.format(diff))
...     return False
...
>>> check_contains({1, 2}, {1, 2, 3})
True
>>> check_contains({1, 2, 3}, {1, 2})
Some elements are missing: set([3])
False

4

Możesz użyć albo set.issubset()lub set.issuperset()(lub ich odpowiedników opartych na operatorach: <=i >=). Zauważ, że metody zaakceptują każdą iterację jako argument, a nie tylko zestaw:

>>> {1, 2}.issubset([1, 2, 3])
True
>>> {1, 2, 3}.issuperset([1, 2])
True

Jeśli jednak używasz operatorów, oba argumenty muszą być ustawione:

>>> {1, 2} <= {1, 2, 3}
True
>>> {1, 2, 3} >= {1, 2}
True

4

Jeśli podejrzewasz, że zbiór jest podzbiorem innego i przecinasz te dwa zbiory razem, wynik jest równy sobie, jeśli jest podzbiorem.

a = [2,1,3,3]
b = [5,4,3,2,1]
set(a).intersection(set(b)) == set(a)
>>True

1
Niech A = set(a)i B = set(b)dla rozsądku. Wtedy to porównanie można skutecznie zredukować do len(A.intersection(B)) == len(A). Oznacza to, że same zestawy nie muszą być porównywane pod względem elementów; wystarczy porównać liczność tych zbiorów. Jednak nawet ta optymalizacja jest prawdopodobnie niewystarczająca, aby uczynić to podejście preferowanym. Dramatycznie bardziej czytelny i wydajny issubset()i <=podejścia są prawie na pewno, co wszyscy chcą.
Cecil Curry

@CecilCurry True - nieprawidłowo użyłem słowa „liczność”, ponieważ jest to pomiar długości. Zaktualizowałem sformułowanie. Twoja optymalizacja jest błędem wynikającym z mojego błędu. To nie jest optymalizacja. Dosłowne sformułowanie „intersection ()” jest bardziej wyraźne niż przeciążone implikacje „> =”, a stwierdzenie, że „issubset ()” jest łatwiejsze do odczytania, jest swego rodzaju eliminacją oczywistości, ponieważ jest to najpopularniejsza odpowiedź. Nie wahaj się wnieść twórczego rozwiązania wykraczającego poza powtarzanie odpowiedzi innych osób.
Jordan Stefanelli

1
>>> set([1,2,3]).issuperset(set([2,1]))
True 
>>>    
>>> set([1,2,3]).issuperset(set([3,5,9]))
False

3
Rozważ prawidłowe sformatowanie odpowiedzi i dodaj wyjaśnienie.
Sam

0

Funkcja poniżej zwraca 0, jeśli lista główna nie zawiera w pełni podlisty i 1, jeśli zawiera pełną.

def islistsubset(sublist,mainlist):
     for item in sublist:
             if item in mainlist:
                     contains = 1
             else:
                     contains = 0
                     break;
     return contains

1
To jest O (n ^ 2) podczas używania operacji na zbiorach, ponieważ w niektórych istniejących odpowiedziach jest znacznie szybsze. Można to również napisać w prosty sposób any(item in mainlist for item in sublist).
Iguananaut

Faktycznie zgadzam się, mógłbym również napisać def islistsubset (podlista, lista główna): zawiera = 1 dla pozycji na liście podrzędnej: jeśli pozycja na liście głównej: kontynuuj else: zawiera = 0 przerwa; powrót zawiera więc tylko 2 zadania na rozmowę
Bobin Motti Thomas

@BobinMottiThomas Możesz bezpośrednio zwrócić True lub False bez tworzenia tymczasowej zmiennej. dla pozycji z listy_a: jeśli pozycji nie ma na liście_b: return False return True
Jordan Stefanelli
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.