Czy istnieje funkcja biblioteki, która wykonuje wyszukiwanie binarne na liście / krotce i zwraca pozycję elementu, jeśli zostanie znaleziona, i „Fałsz” (-1, Brak itd.), Jeśli nie?
Znalazłem funkcje bisect_left / right w module bisect , ale nadal zwracają pozycję, nawet jeśli elementu nie ma na liście. Jest to całkowicie w porządku dla ich zamierzonego zastosowania, ale chcę tylko wiedzieć, czy element znajduje się na liście, czy nie (nie chcę niczego wstawiać).
Pomyślałem o użyciu, bisect_left
a następnie sprawdzeniu, czy pozycja na tej pozycji jest równa temu, czego szukam, ale wydaje się to kłopotliwe (a także muszę sprawdzić, czy liczba może być większa niż największa liczba na mojej liście). Jeśli istnieje ładniejsza metoda, chciałbym się o tym dowiedzieć.
Edytuj Aby wyjaśnić, do czego to jest potrzebne: zdaję sobie sprawę, że słownik bardzo by się do tego nadawał, ale staram się, aby zużycie pamięci było jak najniższe. Moje zamierzone użycie to rodzaj dwukierunkowej tabeli przeglądowej. Mam w tabeli listę wartości i muszę mieć dostęp do wartości na podstawie ich indeksu. Chcę też móc znaleźć indeks określonej wartości lub Brak, jeśli wartość nie znajduje się na liście.
Wykorzystanie do tego słownika byłoby najszybszym sposobem, ale (w przybliżeniu) podwoiłoby wymagania dotyczące pamięci.
Zadałem to pytanie, myśląc, że być może przeoczyłem coś w bibliotekach Pythona. Wygląda na to, że będę musiał napisać własny kod, jak zasugerował Moe.
źródło
np.searchsorted
jest przydatny. docs.scipy.org/doc/numpy/reference/generated/…Odpowiedzi:
źródło
if hi is None: hi = len(a)
Dlaczego nie spojrzeć na kod bisect_left / right i dostosować go do swoich celów.
lubię to:
źródło
hi = mid - 1
welif
?hi = mid
nahi = mid-1
ihi = len(a)
nahi = len(a)-1
iwhile lo < hi:
nawhile lo <= hi
, i byłoby to równoważnie poprawnebisect.bisect_left()
raczej używać niż tego.To trochę nie na temat (ponieważ odpowiedź Moe wydaje się kompletna na pytanie PO), ale warto przyjrzeć się złożoności całej procedury od początku do końca. Jeśli przechowujesz coś na posortowanych listach (w czym pomogłoby wyszukiwanie binarne), a następnie po prostu sprawdzasz istnienie, ponosisz (najgorszy przypadek, chyba że określono):
Posortowane listy
Podczas gdy z a
set()
, ponosiszTo, co naprawdę daje posortowana lista, to „następny”, „poprzedni” i „zakresy” (w tym wstawianie lub usuwanie zakresów), które są O (1) lub O (| zakres |), biorąc pod uwagę indeks początkowy. Jeśli nie używasz często tego rodzaju operacji, przechowywanie w zestawach i sortowanie w celu wyświetlenia może być ogólnie lepszym rozwiązaniem.
set()
powoduje bardzo niewielkie dodatkowe obciążenie w Pythonie.źródło
Warto wspomnieć, że dokumenty w połowie zawierają teraz przykłady wyszukiwania: http://docs.python.org/library/bisect.html#searching-sorted-lists
(Podniesienie wartości ValueError zamiast zwracania -1 lub None jest bardziej pythonowe - na przykład list.index () robi to. Ale oczywiście możesz dostosować przykłady do swoich potrzeb.)
źródło
Najprościej jest użyć połowy i sprawdzić jedną pozycję wstecz, aby zobaczyć, czy element tam jest:
źródło
To jest prosto z instrukcji:
http://docs.python.org/2/library/bisect.html
8.5.1. Wyszukiwanie posortowanych list
Powyższe funkcje bisect () są przydatne do znajdowania punktów wstawiania, ale mogą być trudne lub niewygodne w użyciu w przypadku typowych zadań wyszukiwania. Poniższych pięć funkcji pokazuje, jak przekształcić je w standardowe wyszukiwania posortowanych list:
Tak więc przy niewielkiej modyfikacji Twój kod powinien wyglądać następująco:
źródło
Zgadzam się, że odpowiedź @ DaveAbrahams przy użyciu modułu z połówką jest poprawnym podejściem. W swojej odpowiedzi nie wspomniał o jednym ważnym szczególe.
Z dokumentów
bisect.bisect_left(a, x, lo=0, hi=len(a))
Moduł bisekcji nie wymaga, aby tablica wyszukiwania była obliczana z wyprzedzeniem. Możesz po prostu przedstawić punkty końcowe
bisect.bisect_left
zamiast tego, używając wartości domyślnych0
ilen(a)
.Jeszcze ważniejsze dla mojego zastosowania jest szukanie wartości X takiej, aby zminimalizować błąd danej funkcji. Aby to zrobić, potrzebowałem sposobu, aby algorytm bisect_left wywoływał zamiast tego moje obliczenia. To jest naprawdę proste.
Po prostu podaj obiekt, który definiuje
__getitem__
jakoa
Na przykład, możemy użyć algorytmu bisect, aby znaleźć pierwiastek kwadratowy z dowolną precyzją!
źródło
scipy.optimize
do tego.Jeśli chcesz tylko sprawdzić, czy jest obecny, spróbuj zmienić listę w dykt:
Na moim komputerze polecenie „if n in l” trwało 37 sekund, a „if n in d” 0,4 sekundy.
źródło
Ten jest:
źródło
Rozwiązanie Dave'a Abrahamsa jest dobre. Chociaż zrobiłbym to minimalistycznie:
źródło
Chociaż w Pythonie nie ma jawnego algorytmu wyszukiwania binarnego, istnieje moduł -
bisect
- zaprojektowany do znajdowania punktu wstawienia elementu na posortowanej liście przy użyciu wyszukiwania binarnego. Można to „oszukać” w celu wykonania wyszukiwania binarnego. Największą zaletą tego jest ta sama zaleta, jaką ma większość kodu bibliotecznego - jest bardzo wydajny, dobrze przetestowany i po prostu działa (w szczególności wyszukiwania binarne mogą być dość trudne do pomyślnego wdrożenia - szczególnie jeśli przypadki skrajne nie są dokładnie rozważane).Podstawowe typy
W przypadku podstawowych typów, takich jak Strings lub ints, jest to całkiem proste - wystarczy
bisect
moduł i posortowana lista:Możesz również użyć tego, aby znaleźć duplikaty:
Oczywiście w razie potrzeby możesz po prostu zwrócić indeks, a nie wartość tego indeksu.
Obiekty
W przypadku niestandardowych typów lub obiektów sprawy są nieco trudniejsze: musisz zaimplementować bogate metody porównywania, aby uzyskać połowę w celu prawidłowego porównania.
Powinno to działać przynajmniej w Pythonie 2.7 -> 3.3
źródło
Używanie dyktowania nie podwoiłoby zużycia pamięci, chyba że przechowywane obiekty są naprawdę małe, ponieważ wartości są tylko wskaźnikami do rzeczywistych obiektów:
W tym przykładzie „foo” jest przechowywane tylko raz. Czy to ma dla ciebie znaczenie? A o ilu dokładnie rzeczach mówimy?
źródło
Ten kod działa z listami liczb całkowitych w sposób rekurencyjny. Szuka najprostszego scenariusza, który jest następujący: długość listy mniejsza niż 2. Oznacza to, że odpowiedź już istnieje i wykonywany jest test w celu sprawdzenia poprawnej odpowiedzi. Jeśli nie, ustawiana jest wartość środkowa i sprawdzana, czy jest poprawna, jeśli nie bisekcja jest wykonywana przez ponowne wywołanie funkcji, ale ustawienie środkowej wartości jako górnej lub dolnej granicy, przesuwając ją w lewo lub w prawo
źródło
Sprawdź przykłady w Wikipedii http://en.wikipedia.org/wiki/Binary_search_algorithm
źródło
Myślę, że jest to znacznie lepsze i skuteczne. proszę mnie poprawić :) . Dziękuję Ci
źródło
s
to lista.binary(s, 0, len(s) - 1, find)
jest pierwszym wezwaniem.Funkcja zwraca indeks poszukiwanego elementu. Jeśli nie ma takiej pozycji, zwraca
-1
.źródło
źródło
Wyszukiwanie binarne:
// Aby wywołać powyższą funkcję użyj:
źródło
Potrzebowałem wyszukiwania binarnego w Pythonie i generycznego dla modeli Django. W modelach Django jeden model może mieć klucz obcy do innego modelu i chciałem przeprowadzić wyszukiwanie na obiektach pobranych modeli. Napisałem następującą funkcję, której możesz użyć.
źródło
Wiele dobrych rozwiązań powyżej, ale nie widziałem prostego (KISS, zachowaj prostotę (bo jestem)) głupiego użycia wbudowanej w Pythonie / generycznej funkcji dwusiecznej do wyszukiwania binarnego. Przy odrobinie kodu wokół funkcji połowy, Myślę, że mam poniżej przykład, w którym przetestowałem wszystkie przypadki dla małej tablicy nazw. Niektóre z powyższych rozwiązań nawiązują do tego / mówią, ale mam nadzieję, że poniższy prosty kod pomoże każdemu zdezorientowanemu, tak jak ja.
Python bisect służy do wskazania, gdzie wstawić nową wartość / element wyszukiwania do posortowanej listy. Poniższy kod, który używa bisect_left, który zwróci indeks trafienia, jeśli szukany element na liście / tablicy zostanie znaleziony (Uwaga: bisect i bisect_right zwróci indeks elementu po trafieniu lub dopasuje jako punkt wstawienia) Jeśli nie zostanie znaleziony , bisect_left zwróci indeks do następnego elementu na posortowanej liście, który nie == szukanej wartości. Jedynym innym przypadkiem jest sytuacja, w której element wyszukiwania znalazłby się na końcu listy, gdzie zwracany indeks byłby poza końcem listy / tablicy, a który w kodzie poniżej wczesnego wyjścia przez Pythona z uchwytami logicznymi "i". (pierwszy warunek Fałsz Python nie sprawdza kolejnych warunków)
źródło