Jaki jest najszybszy sposób sprawdzenia, czy wartość istnieje na liście (lista zawierająca miliony wartości) i jaki jest jej indeks?
Wiem, że wszystkie wartości na liście są unikalne, jak w tym przykładzie.
Pierwszą metodą, którą wypróbowałem, jest (3,8 s w moim prawdziwym kodzie):
a = [4,2,3,1,5,6]
if a.count(7) == 1:
b=a.index(7)
"Do something with variable b"
Drugą metodą, którą próbuję, jest (2x szybszy: 1,9 s dla mojego prawdziwego kodu):
a = [4,2,3,1,5,6]
try:
b=a.index(7)
except ValueError:
"Do nothing"
else:
"Do something with variable b"
Proponowane metody od użytkownika Przepełnienie stosu (2,74 s dla mojego prawdziwego kodu):
a = [4,2,3,1,5,6]
if 7 in a:
a.index(7)
W moim prawdziwym kodzie pierwsza metoda zajmuje 3,81 sekundy, a druga metoda 1,88 sekundy. To dobra poprawa, ale:
Jestem początkującym w Pythonie / skryptach i czy istnieje szybszy sposób na robienie tych samych rzeczy i oszczędność czasu?
Bardziej szczegółowe wyjaśnienie mojej aplikacji:
W interfejsie API Blendera mogę uzyskać dostęp do listy cząstek:
particles = [1, 2, 3, 4, etc.]
Stamtąd mogę uzyskać dostęp do lokalizacji cząsteczki:
particles[x].location = [x,y,z]
I dla każdej cząstki sprawdzam, czy sąsiad istnieje, przeszukując każdą lokalizację cząstek w ten sposób:
if [x+1,y,z] in particles.location
"Find the identity of this neighbour particle in x:the particle's index
in the array"
particles.index([x+1,y,z])
źródło
bisect
Odpowiedzi:
Najczystszy i najszybszy sposób na zrobienie tego.
Możesz również rozważyć użycie
set
zestawu, ale utworzenie tego zestawu z listy może zająć więcej czasu niż zaoszczędzi szybsze testowanie członkostwa. Jedynym sposobem, aby być pewnym, jest dokładne porównanie. (zależy to również od wymaganych operacji)źródło
Jak twierdzą inni,
in
może być bardzo powolny w przypadku dużych list. Oto kilka porównań występów dlain
,set
ibisect
. Zauważ, że czas (w sekundach) jest w skali logarytmicznej.Kod do testowania:
źródło
import random / import bisect / import matplotlib.pyplot as plt
a następnie zadzwoń:profile()
range()
obiekcie. Podczas używaniavar in [integer list]
sprawdź, czyrange()
obiekt może modelować tę samą sekwencję. Bardzo zbliżony do zestawu, ale bardziej zwięzły.Możesz umieścić swoje przedmioty w
set
. Wyszukiwanie zestawów jest bardzo wydajne.Próbować:
edytuj W komentarzu mówisz, że chcesz uzyskać indeks elementu. Niestety zestawy nie mają pojęcia pozycji elementu. Alternatywą jest wstępne sortowanie listy, a następnie wyszukiwanie binarne za każdym razem, gdy trzeba znaleźć element.
źródło
Stosowanie
Uważam, że jest to najszybszy sposób na sprawdzenie, czy wybrana wartość znajduje się w tablicy.
źródło
return 'a' in a
?o='--skip'; o in ("--skip-ias"); # returns True !
in
operator działa w ten sam sposób, aby przetestować członkostwo w podciągu. Mylące jest tutaj to, że prawdopodobnie("hello")
nie jest to krotka o pojedynczej wartości, podczas gdy("hello",)
jest - przecinek robi różnicę.o in ("--skip-ias",)
jestFalse
zgodnie z oczekiwaniami.Będzie to dobry pomysł tylko wtedy, gdy nie zmieni się, dlatego możemy raz wykonać część dict (), a następnie użyć jej wielokrotnie. Jeśli coś się zmieni, podaj więcej szczegółów na temat tego, co robisz.
źródło
Pierwotne pytanie brzmiało:
Zatem są dwie rzeczy do znalezienia:
W tym celu zmodyfikowałem kod @xslittlegrass, aby obliczać indeksy we wszystkich przypadkach, i dodałem dodatkową metodę.
Wyniki
Metody to:
Wyniki pokazują, że metoda 5 jest najszybsza.
Co ciekawe, try i ustawione metody są równoważne w czasie.
Kod testowy
źródło
Wygląda na to, że Twoja aplikacja może zyskać na zastosowaniu struktury danych Bloom Filter.
Krótko mówiąc, wyszukiwanie filtra Blooma może bardzo szybko stwierdzić, czy wartość NIE JEST ZDECYDOWO obecna w zestawie. W przeciwnym razie możesz wykonać wolniejsze wyszukiwanie, aby uzyskać indeks wartości, KTÓRE MOŻLIWE MOGĄ BYĆ na liście. Jeśli więc twoja aplikacja ma tendencję do uzyskiwania wyniku „nie znaleziono” znacznie częściej niż wynik „znaleziono”, możesz przyspieszyć dodając Filtr Blooma.
Aby uzyskać szczegółowe informacje, Wikipedia zapewnia dobry przegląd działania filtrów Blooma, a wyszukiwanie w Internecie dla „biblioteki filtrów filtrów python” zapewni co najmniej kilka przydatnych implementacji.
źródło
Należy pamiętać, że
in
operator testuje nie tylko równość (==
), ale także tożsamość (is
),in
logika dlalist
s jest mniej więcej równoważna z następującą (jest napisana w C, a nie w Pythonie, przynajmniej w CPython):W większości przypadków ten szczegół jest nieistotny, ale w niektórych okolicznościach może zaskoczyć nowicjusza w Pythonie, na przykład
numpy.NAN
ma niezwykłą właściwość polegającą na tym, że nie jest sobie równy :Aby rozróżnić te niezwykłe przypadki, możesz użyć
any()
:Zauważ, że
in
logika dlalist
s zany()
będzie następująca:Powinienem jednak podkreślić, że jest to przypadek skrajny i dla zdecydowanej większości przypadków
in
operator jest wysoce zoptymalizowany i dokładnie tego, czego chcesz oczywiście (albo z alist
albo zset
).źródło
Lub użyj
__contains__
:Próbny:
źródło
Rozwiązanie @Winston Ewert zapewnia duże przyspieszenie dla bardzo dużych list, ale ta odpowiedź na przepełnienie stosu wskazuje, że próba: / wyjątek: / else: konstrukcja zostanie spowolniona, jeśli gałąź wyjątków jest często osiągana. Alternatywą jest skorzystanie z
.get()
metody dyktowania:Ta
.get(key, default)
metoda jest tylko w przypadku, gdy nie możesz zagwarantować, że klucz będzie w nagraniu. Jeśli klucz jest obecny, zwraca wartość (jak by to zrobiłdict[key]
), ale gdy nie jest,.get()
zwraca wartość domyślną (tutajNone
). W takim przypadku musisz upewnić się, że wybrane ustawienie domyślne nie będzie dostępnea
.źródło
To nie jest kod, ale algorytm bardzo szybkiego wyszukiwania.
Jeśli twoja lista i szukana wartość są liczbami, jest to dość proste. Jeśli ciągi znaków: spójrz na dół:
Jeśli potrzebujesz także oryginalnej pozycji swojego numeru, poszukaj jej w drugiej kolumnie indeksu.
Jeśli lista nie zawiera liczb, metoda nadal działa i będzie najszybsza, ale może być konieczne zdefiniowanie funkcji, która może porównywać / porządkować ciągi znaków.
Oczywiście wymaga to inwestycji metody sorted (), ale jeśli nadal używasz tej samej listy do sprawdzania, być może warto.
źródło
Ponieważ pytanie nie zawsze powinno być rozumiane jako najszybszy sposób techniczny - zawsze sugeruję najprostszy najszybszy sposób na zrozumienie / napisanie: zrozumienie listy, jedno-liniowy
Miałem
list_to_search_in
wszystkie elementy i chciałem zwrócić indeksy elementów wlist_from_which_to_search
.To zwraca indeksy na ładnej liście.
Istnieją inne sposoby sprawdzenia tego problemu - jednak listy ze zrozumieniem są wystarczająco szybkie, dodatkowo dodając fakt, że pisanie jest wystarczająco szybkie, aby rozwiązać problem.
źródło
Dla mnie było to 0,030 s (rzeczywiste), 0,026 s (użytkownik) i 0,004 s (sys).
źródło
Kod sprawdzający, czy w tablicy istnieją dwa elementy, których iloczyn równa się k:
źródło