Saya akan mengganti nama fungsi take_closestagar sesuai dengan konvensi penamaan PEP8.
Jika yang Anda maksud adalah eksekusi cepat dan bukan penulisan cepat, minseharusnya tidak menjadi senjata pilihan Anda, kecuali dalam satu kasus penggunaan yang sangat sempit. The minsolusi perlu memeriksa setiap nomor dalam daftar dan melakukan perhitungan untuk setiap nomor. bisect.bisect_leftSebaliknya, menggunakan hampir selalu lebih cepat.
"Hampir" berasal dari fakta yang bisect_leftmengharuskan daftar harus diurutkan untuk bekerja. Mudah-mudahan, use case Anda sedemikian rupa sehingga Anda dapat mengurutkan daftar sekali dan kemudian membiarkannya sendiri. Meskipun tidak, selama Anda tidak perlu menyortir sebelum setiap kali Anda menelepon take_closest, bisectmodul tersebut kemungkinan akan keluar di atas. Jika Anda ragu, coba keduanya dan lihat perbedaan dunia nyata.
from bisect import bisect_left
def take_closest(myList, myNumber):
"""
Assumes myList is sorted. Returns closest value to myNumber.
If two numbers are equally close, return the smallest number.
"""
pos = bisect_left(myList, myNumber)
if pos == 0:
return myList[0]
if pos == len(myList):
return myList[-1]
before = myList[pos - 1]
after = myList[pos]
if after - myNumber < myNumber - before:
return after
else:
return before
Bisect bekerja dengan berulang kali membagi dua daftar dan mencari tahu bagian mana yang myNumberharus diambil dengan melihat nilai tengahnya. Ini berarti ia memiliki waktu berjalan O (log n) sebagai kebalikan dari O (n) waktu berjalan jawaban tertinggi yang dipilih . Jika kami membandingkan kedua metode dan menyediakan keduanya dengan diurutkan myList, ini adalah hasilnya:
$ python -m timeit -s "
dari impor take_closest terdekat
dari randint impor acak
a = range (-1000, 1000, 10) "" take_closest (a, randint (-1100, 1100)) "
100000 loop, terbaik 3: 2,22 usec per loop
$ python -m timeit -s "
dari impor terdekat with_min
dari randint impor acak
a = range (-1000, 1000, 10) "" with_min (a, randint (-1100, 1100)) "
10.000 loop, terbaik dari 3: 43.9 USD per loop
Jadi dalam tes khusus ini, bisecthampir 20 kali lebih cepat. Untuk daftar yang lebih panjang, perbedaannya akan lebih besar.
Bagaimana jika kita meratakan lapangan bermain dengan menghapus prasyarat yang myListharus diurutkan? Katakanlah kita mengurutkan salinan daftar setiap kali take_closest dipanggil, sementara membiarkan minsolusinya tidak berubah. Menggunakan daftar 200-item dalam tes di atas, bisectsolusinya masih yang tercepat, meskipun hanya sekitar 30%.
Ini adalah hasil yang aneh, mengingat langkah penyortirannya adalah O (n log (n)) ! Satu-satunya alasan minyang masih kalah adalah bahwa penyortiran dilakukan dalam kode c yang sangat dioptimalkan, sementara minharus bersusah payah memanggil fungsi lambda untuk setiap item. Seiring myListbertambahnya ukuran, minsolusinya pada akhirnya akan lebih cepat. Perhatikan bahwa kami harus menumpuk segalanya agar minsolusi dapat menang.