Apakah ada fungsi perpustakaan yang melakukan pencarian biner pada daftar / tuple dan mengembalikan posisi item jika ditemukan dan 'Salah' (-1, Tidak ada, dll.) Jika tidak?
Saya menemukan fungsi bisect_left / right di modul bisect , tetapi mereka tetap mengembalikan posisi walaupun item tersebut tidak ada dalam daftar. Itu sangat baik untuk penggunaan yang dimaksudkan, tetapi saya hanya ingin tahu apakah suatu item ada dalam daftar atau tidak (tidak ingin memasukkan apa pun).
Saya berpikir untuk menggunakan bisect_left
dan kemudian memeriksa apakah item pada posisi itu sama dengan apa yang saya cari, tetapi tampaknya rumit (dan saya juga perlu melakukan pengecekan batas jika jumlahnya bisa lebih besar dari jumlah terbesar dalam daftar saya). Jika ada metode yang lebih baik saya ingin tahu tentang itu.
Sunting Untuk mengklarifikasi untuk apa saya memerlukan ini: Saya sadar bahwa kamus akan sangat cocok untuk ini, tetapi saya mencoba untuk menjaga konsumsi memori serendah mungkin. Penggunaan yang saya maksudkan akan menjadi semacam tabel pencarian dua arah. Saya sudah dalam tabel daftar nilai dan saya harus dapat mengakses nilai-nilai berdasarkan indeks mereka. Dan saya juga ingin dapat menemukan indeks nilai tertentu atau Tidak ada jika nilainya tidak ada dalam daftar.
Menggunakan kamus untuk ini akan menjadi cara tercepat, tetapi akan (kurang-lebih) menggandakan persyaratan memori.
Saya mengajukan pertanyaan ini berpikir bahwa saya mungkin telah mengabaikan sesuatu di perpustakaan Python. Sepertinya saya harus menulis kode sendiri, seperti yang disarankan Moe.
sumber
np.searchsorted
bermanfaat. docs.scipy.org/doc/numpy/reference/generated/…Jawaban:
sumber
if hi is None: hi = len(a)
Mengapa tidak melihat kode untuk bisect_left / right dan menyesuaikannya sesuai dengan tujuan Anda.
seperti ini:
sumber
hi = mid - 1
di dalamelif
?hi = mid
kehi = mid-1
danhi = len(a)
kehi = len(a)-1
danwhile lo < hi:
kewhile lo <= hi
, dan itu akan sama benarbisect.bisect_left()
daripada ini.Ini sedikit di luar topik (karena jawaban Moe tampaknya lengkap untuk pertanyaan OP), tetapi mungkin layak untuk melihat kompleksitas untuk seluruh prosedur Anda dari ujung ke ujung. Jika Anda menyimpan sesuatu di daftar yang disortir (yang mana pencarian biner akan membantu), dan kemudian hanya memeriksa keberadaannya, Anda mengalami (kasus terburuk, kecuali ditentukan):
Daftar yang Diurutkan
Sedangkan dengan
set()
, Anda dikenaiHal yang benar-benar Anda dapatkan dari daftar yang disortir adalah "berikutnya", "sebelumnya", dan "rentang" (termasuk rentang menyisipkan atau menghapus), yaitu O (1) atau O (| range |), diberi indeks awal. Jika Anda tidak sering menggunakan operasi semacam itu, maka menyimpan sebagai set, dan menyortir untuk tampilan mungkin merupakan kesepakatan yang lebih baik secara keseluruhan.
set()
mengeluarkan sedikit biaya tambahan tambahan dalam python.sumber
Mungkin perlu disebutkan bahwa dokumen dua bagian sekarang menyediakan contoh pencarian: http://docs.python.org/library/bisect.html#searching-sorted-lists
(Meningkatkan ValueError daripada mengembalikan -1 atau Tidak ada lebih pythonic - list.index () melakukannya, misalnya. Tapi tentu saja Anda dapat menyesuaikan contoh dengan kebutuhan Anda.)
sumber
Paling sederhana adalah dengan menggunakan dua bagian dan periksa satu posisi kembali untuk melihat apakah item ada di sana:
sumber
Ini benar dari manual:
http://docs.python.org/2/library/bisect.html
8.5.1. Mencari Daftar yang Diurutkan
Fungsi membagi dua () berguna untuk menemukan titik penyisipan tetapi bisa rumit atau canggung untuk digunakan untuk tugas pencarian umum. Lima fungsi berikut ini menunjukkan cara mengubahnya menjadi pencarian standar untuk daftar yang diurutkan:
Jadi dengan sedikit modifikasi kode Anda harus:
sumber
Saya setuju bahwa jawaban @ DaveAbrahams menggunakan modul dua bagian adalah pendekatan yang benar. Dia tidak menyebutkan satu detail penting dalam jawabannya.
Dari dokumen
bisect.bisect_left(a, x, lo=0, hi=len(a))
Modul pembagian dua tidak memerlukan array pencarian yang harus dihitung sebelumnya. Anda bisa menyajikan titik akhir ke
bisect.bisect_left
bukan menggunakan menggunakan default0
danlen(a)
.Bahkan lebih penting untuk saya gunakan, mencari nilai X sedemikian rupa sehingga kesalahan fungsi yang diberikan diminimalkan. Untuk melakukan itu, saya membutuhkan cara agar algoritma bisect_left memanggil komputasi saya sebagai gantinya. Ini sangat sederhana.
Cukup sediakan objek yang didefinisikan
__getitem__
sebagaia
Sebagai contoh, kita bisa menggunakan algoritme dua-bagian untuk menemukan akar kuadrat dengan presisi sewenang-wenang!
sumber
scipy.optimize
untuk ini.Jika Anda hanya ingin melihat apakah ada, coba ubah daftar menjadi dict:
Di mesin saya, "if n in l" butuh 37 detik, sementara "if n in d" butuh 0,4 detik.
sumber
Yang ini adalah:
sumber
Solusi Dave Abrahams baik. Meskipun saya akan melakukannya minimalis:
sumber
Meskipun tidak ada algoritma pencarian biner eksplisit di Python, ada modul -
bisect
- yang dirancang untuk menemukan titik penyisipan elemen dalam daftar yang diurutkan menggunakan pencarian biner. Ini bisa "diakali" untuk melakukan pencarian biner. Keuntungan terbesar dari ini adalah keuntungan yang sama dengan kode perpustakaan - ini berkinerja tinggi, teruji dengan baik dan hanya berfungsi (pencarian biner pada khususnya bisa sangat sulit untuk diterapkan dengan sukses - terutama jika kasus tepi tidak dipertimbangkan dengan hati-hati).Tipe Dasar
Untuk tipe dasar seperti Strings atau ints sangat mudah - yang Anda butuhkan hanyalah
bisect
modul dan daftar yang diurutkan:Anda juga dapat menggunakan ini untuk menemukan duplikat:
Jelas Anda hanya bisa mengembalikan indeks daripada nilai pada indeks itu jika diinginkan.
Benda
Untuk jenis atau objek khusus, hal-hal sedikit lebih rumit: Anda harus memastikan untuk menerapkan metode perbandingan kaya agar bisect untuk membandingkan dengan benar.
Ini harus bekerja setidaknya di Python 2.7 -> 3.3
sumber
Menggunakan dict tidak akan suka menggandakan penggunaan memori Anda kecuali objek yang Anda simpan benar-benar kecil, karena nilainya hanya petunjuk ke objek yang sebenarnya:
Dalam contoh itu, 'foo' hanya disimpan satu kali. Apakah itu membuat perbedaan bagi Anda? Dan berapa banyak barang yang kita bicarakan?
sumber
Kode ini berfungsi dengan daftar bilangan bulat dengan cara rekursif. Mencari skenario kasus paling sederhana, yaitu: panjang daftar kurang dari 2. Ini berarti jawabannya sudah ada di sana dan tes dilakukan untuk memeriksa jawaban yang benar. Jika tidak, nilai tengah ditetapkan dan diuji untuk menjadi benar, jika tidak membagi dua dilakukan dengan memanggil lagi fungsi, tetapi menetapkan nilai tengah sebagai batas atas atau bawah, dengan menggesernya ke kiri atau kanan.
sumber
Lihatlah contoh-contoh di Wikipedia http://en.wikipedia.org/wiki/Binary_search_algorithm
sumber
Saya kira ini jauh lebih baik dan efektif. tolong perbaiki saya :). Terima kasih
sumber
s
adalah daftar.binary(s, 0, len(s) - 1, find)
adalah panggilan awal.Fungsi mengembalikan indeks item yang diminta. Jika tidak ada barang yang dikembalikan
-1
.sumber
sumber
Pencarian Biner:
// Untuk memanggil fungsi di atas gunakan:
sumber
Saya membutuhkan pencarian biner dalam python dan generik untuk model Django. Dalam model Django, satu model dapat memiliki kunci asing ke model lain dan saya ingin melakukan beberapa pencarian pada objek model yang diambil. Saya menulis fungsi berikut Anda dapat menggunakan ini.
sumber
Banyak solusi bagus di atas tetapi saya belum melihat yang sederhana (CIUM membuatnya sederhana (karena saya) bodoh menggunakan Python built in / fungsi membagi dua generik untuk melakukan pencarian biner. Dengan sedikit kode di sekitar fungsi membagi dua, Saya pikir saya punya contoh di bawah ini di mana saya telah menguji semua kasus untuk array string nama kecil. Beberapa solusi di atas menyinggung / mengatakan ini, tetapi mudah-mudahan kode sederhana di bawah ini akan membantu orang yang bingung seperti saya.
Python bisect digunakan untuk menunjukkan di mana memasukkan nilai baru / item pencarian ke dalam daftar yang diurutkan. Kode di bawah ini yang menggunakan bisect_left yang akan mengembalikan indeks klik jika item pencarian dalam daftar / array ditemukan (Catatan bisect_right akan mengembalikan indeks elemen setelah hit atau cocok sebagai titik penyisipan) Jika tidak ditemukan , bisect_left akan mengembalikan indeks ke item berikutnya dalam daftar yang diurutkan yang tidak akan == nilai pencarian. Satu-satunya kasus lain adalah di mana item pencarian akan pergi di akhir daftar di mana indeks kembali akan berada di luar akhir daftar / array, dan yang dalam kode di bawah pintu keluar awal oleh Python dengan "dan" pegangan logika. (kondisi pertama False Python tidak memeriksa kondisi selanjutnya)
sumber