Powiedzmy, że mam dwie listy l1
i l2
. Chcę wykonać l1 - l2
, która zwraca wszystkie elementy l1
nie w l2
.
Mogę wymyślić naiwne podejście do tego, ale będzie to naprawdę nieefektywne. Jaki jest pytoniczny i skuteczny sposób to zrobić?
Jako przykład, jeśli mam l1 = [1,2,6,8] and l2 = [2,3,5,8]
, l1 - l2
powinien wrócić[1,6]
Odpowiedzi:
Python ma funkcję językową o nazwie Listy, która doskonale nadaje się do tego, aby tego rodzaju rzeczy były niezwykle łatwe. Poniższa instrukcja robi dokładnie to, co chcesz i zapisuje wynik
l3
:l3
będzie zawierać[1, 6]
.źródło
in
operator nie jest tak wydajny na liście.in
na liście jest O (n), podczas gdyin
na zestawie jest O (1). Jednak dopóki nie dojdziesz do tysięcy elementów lub więcej, raczej nie zauważysz różnicy.l3 = [x for x in l1 if x not in set(l2)]
? Jestem pewien, czyset(l2)
zostałbym powołany więcej niż jeden raz.l2s = set(l2)
a następnie powiedziećl3 = [x for x in l1 if x not in l2s]
. Nieco łatwiej.Jednym ze sposobów jest użycie zestawów:
źródło
l1
, co może być niepożądanym efektem ubocznym.timeit.timeit('a = [1,2,3,4]; b = [1,3]; c = [i for i in a if a not in b]', number=100000) -> 0.12061533199999985
timeit.timeit('a = {1,2,3,4}; b = {1,3}; c = a - b', number=100000) -> 0.04106225999998969
. Więc jeśli wydajność jest znaczącym czynnikiem, ta odpowiedź może być bardziej odpowiednia (a także, jeśli nie obchodzi cię duplikat lub zamówienie)Alternatywnie możesz również użyć
filter
wyrażenia lambda, aby uzyskać pożądany wynik. Na przykład:Porównanie wydajności
Tutaj porównuję wyniki wszystkich wymienionych tutaj odpowiedzi. Zgodnie z oczekiwaniami operacja
set
oparta na Arkku jest najszybsza.Różnica zestawu Arkku - pierwsza ( 0,122 usec na pętlę)
Zrozumienie listy Daniela Prydena z
set
wyszukiwaniem - drugie (0,302 usec na pętlę)Zrozumienie listy pączków na zwykłej liście - trzecia (0,552 usec na pętlę)
Używanie Moinuddina Quadri
filter
- czwarte (0,972 usec na pętlę)Akshay Hazari używa kombinacji
reduce
+filter
- piąta (3,97 usec na pętlę)PS:
set
nie utrzymuje kolejności i usuwa zduplikowane elementy z listy. Dlatego nie używaj ustawionej różnicy, jeśli potrzebujesz którejkolwiek z nich.źródło
Rozwijając odpowiedź Donut i inne odpowiedzi tutaj, możesz uzyskać jeszcze lepsze wyniki, używając zrozumienia generatora zamiast zrozumienia listy i
set
struktury danych (ponieważin
operator jest O (n) na liście, ale O (1) na planie).Oto funkcja, która zadziała dla Ciebie:
Wynik będzie iterowalny, który leniwie pobierze przefiltrowaną listę. Jeśli potrzebujesz prawdziwego obiektu listy (np. Jeśli musisz zrobić
len()
na wyniku), możesz łatwo zbudować listę w ten sposób:źródło
Użyj typu zestawu Python. To byłoby najbardziej pytoniczne. :)
Ponadto, ponieważ jest natywny, powinna być również najbardziej zoptymalizowaną metodą.
Widzieć:
http://docs.python.org/library/stdtypes.html#set
http://docs.python.org/library/sets.htm (dla starszych python)
źródło
l1
zawiera powtarzające się elementy.użyj Ustawić wyrażenia {x dla x w l2} lub ustaw (l2), aby uzyskać zestaw, a następnie użyj Wyjaśnienia listy, aby uzyskać listę
kod testu porównawczego:
wynik testu porównawczego:
źródło
l2set = set( l2 )
zamiastl2set = { x for x in l2 }
Alternatywne rozwiązanie:
źródło