Krótka odpowiedź: użyj not set(a).isdisjoint(b)
, to zwykle najszybszy.
Istnieją cztery popularne sposoby testowania, czy dwie listy a
i b
udostępniają jakiekolwiek elementy. Pierwsza opcja jest przekształcenie zarówno do zestawów i sprawdzić ich przecięcia, jako takich:
bool(set(a) & set(b))
Ponieważ zestawy są przechowywane przy użyciu tabeli mieszania w Pythonie, szukając ich jest O(1)
(patrz here uzyskać więcej informacji na temat złożoności operatorzy w Pythonie). Teoretycznie jest to O(n+m)
średnio dla obiektów n
i m
na listach a
i b
. Ale 1) musi najpierw utworzyć zestawy z list, które mogą trwać niezauważalnie długo i 2) zakłada, że kolizje mieszania są rzadkie wśród danych.
Drugi sposób to zrobić jest użycie wyrażenia generatora wykonywania iteracji na listach, takich jak:
any(i in a for i in b)
Pozwala to, aby szukać w miejscu, więc żadna nowa pamięć jest alokowana do zmiennych pośredniczących. Dotyczy to również pierwszego znaleziska. Ale operator in
jest zawsze O(n)
na listach (patrz).
Innym proponowanym rozwiązaniem jest iterate hybridto przez jeden z listy, przekształcić drugi w zbiorze oraz testu dla członkostwa na tym zestawie, tak jak poniżej:
a = set(a); any(i in a for i in b)
Czwarte podejście do skorzystania z metoda isdisjoint()
z (mrożone) zestawów (patrz here), na przykład:
not set(a).isdisjoint(b)
Jeśli elementy Wyszukiwane są blisko początku tablicy (np to jest posortowana), wyrażenie generator jest faworyzowany, jak zestawy przecinają mnie TZT trzeba przydzielić nową pamięć dla zmiennych pośredniczących:
from timeit import timeit
>>> timeit('bool(set(a) & set(b))', setup="a=list(range(1000));b=list(range(1000))", number=100000)
26.077727576019242
>>> timeit('any(i in a for i in b)', setup="a=list(range(1000));b=list(range(1000))", number=100000)
0.16220548999262974
Oto wykres czasu wykonania dla tego przykładu, w zależności od wielkości listy:
Należy zauważyć, że obie osie są logarytmiczna. Jest to najlepszy przypadek dla wyrażenia generatora. Jak widać, metoda isdisjoint()
jest lepsza dla bardzo małych rozmiarów list, podczas gdy wyrażenie generatora jest lepsze dla większych rozmiarów list.
Z drugiej strony, gdy wyszukiwanie rozpoczyna się od początku wyrażenia hybrydowego i generatora, jeśli element wspólny jest systematycznie na końcu tablicy (lub obie listy nie współdzielą żadnych wartości), rozłączne i ustawione podejścia skrzyżowania są wtedy znacznie szybsze niż ekspresja generatora i podejście hybrydowe.
>>> timeit('any(i in a for i in b)', setup="a=list(range(1000));b=[x+998 for x in range(999,0,-1)]", number=1000))
13.739536046981812
>>> timeit('bool(set(a) & set(b))', setup="a=list(range(1000));b=[x+998 for x in range(999,0,-1)]", number=1000))
0.08102107048034668
Ciekawostką jest, aby pamiętać, że wyrażenie generator jest sposób wolniej lista większych rozmiarach. To jest tylko dla 1000 powtórzeń, zamiast 100000 dla poprzedniej figury. Ta konfiguracja jest również dobrze przybliżona, gdy nie są udostępniane żadne elementy, i jest najlepszym rozwiązaniem dla podejść rozłącznych i zestawionych przecięć.
Oto dwa analiza za pomocą liczb losowych (zamiast olinowanie konfigurację do faworyzowania jednej techniki lub inny):
wysoka szansa dzielenia: Elementy są losowo z [1, 2*len(a)]
. Niska szansa na udostępnienie: elementy są losowo pobierane z [1, 1000*len(a)]
.
Do tej pory ta analiza zakładała, że obie listy mają ten sam rozmiar.W przypadku dwóch list o różnych rozmiarach, na przykład a
jest znacznie mniejsze, isdisjoint()
zawsze jest szybsze:
Upewnij się, że lista a
jest mniejszy, w przeciwnym razie wydajność spada. W tym eksperymencie rozmiar listy a
ustalono jako stały na 5
.
Podsumowując:
- Jeśli listy są bardzo małe (< 10 elementów),
not set(a).isdisjoint(b)
zawsze jest najszybszy.
- Jeśli elementy na liście są posortowane lub mają regularną strukturę, z której można skorzystać, wyrażenie generatora
any(i in a for i in b)
jest najszybsze na dużych rozmiarach list;
- Sprawdź zestaw skrzyżowania z
not set(a).isdisjoint(b)
, który zawsze jest szybszy niż bool(set(a) & set(b))
.
- Hybrydowa "lista iteracji, test na zestawie"
a = set(a); any(i in a for i in b)
jest generalnie wolniejsza niż inne metody.
- Wyrażenie generatora i hybryda są znacznie wolniejsze niż dwa inne podejścia, jeśli chodzi o listy bez elementów współużytkowania.
W większości przypadków najlepszym rozwiązaniem jest użycie metody isdisjoint()
, ponieważ wyrażenie generatora będzie trwało dłużej, ponieważ jest bardzo nieefektywne, gdy nie są udostępniane żadne elementy.
Jedyne optymalizacje jakie mogę sobie wyobrazić to opuszczenie 'len (...)> 0' ponieważ' bool (set ([])) daje Fałsz. I oczywiście, jeśli zachowasz swoje listy jako zestawy, możesz zaoszczędzić na narzucie ustawionego zestawu. – msw
Ważne: https://stackoverflow.com/a/44786707/1959808 –
Należy zauważyć, że nie można odróżnić 'True' od' 1' i 'False' od' 0'. 'not set ([1]). isdisjoint ([True])' dostaje 'True', to samo z innymi rozwiązaniami. – Dimali