คำถามเดิมคือ:
วิธีที่เร็วที่สุดที่จะทราบว่ามีค่าอยู่ในรายการ (รายการที่มีค่าหลายล้านค่าอยู่ในรายการ) และดัชนีคืออะไร
ดังนั้นจึงมีสองสิ่งที่จะค้นหา:
- เป็นรายการในรายการและ
- ดัชนีคืออะไร (ถ้าอยู่ในรายการ)
ต่อสิ่งนี้ฉันแก้ไขรหัส @xslittlegrass เพื่อคำนวณดัชนีในทุกกรณีและเพิ่มวิธีเพิ่มเติม
ผล
วิธีการคือ:
- ใน - โดยทั่วไปถ้า x ใน b: คืน b.index (x)
- ลอง - ลอง / จับบน b.index (x) (ข้ามต้องตรวจสอบว่า x เป็น b)
- ชุด - โดยทั่วไปถ้า x ในชุด (b): return b.index (x)
- bisect - จัดเรียง b ด้วยดัชนีของมันค้นหาไบนารีสำหรับ x ในเรียงลำดับ (b) Note mod จาก @xslittlegrass ที่ส่งคืนดัชนีใน b ที่เรียงลำดับแทนที่จะเป็น b ดั้งเดิม)
- ย้อนกลับ - สร้างพจนานุกรมค้นหาแบบย้อนกลับ d สำหรับ b; จากนั้น d [x] ให้ดัชนีของ x
ผลลัพธ์แสดงว่าวิธีที่ 5 นั้นเร็วที่สุด
ที่น่าสนใจลองและวิธีการตั้งค่าจะเทียบเท่าในเวลา
รหัสทดสอบ
import random
import bisect
import matplotlib.pyplot as plt
import math
import timeit
import itertools
def wrapper(func, *args, **kwargs):
" Use to produced 0 argument function for call it"
# Reference https://www.pythoncentral.io/time-a-python-function/
def wrapped():
return func(*args, **kwargs)
return wrapped
def method_in(a,b,c):
for i,x in enumerate(a):
if x in b:
c[i] = b.index(x)
else:
c[i] = -1
return c
def method_try(a,b,c):
for i, x in enumerate(a):
try:
c[i] = b.index(x)
except ValueError:
c[i] = -1
def method_set_in(a,b,c):
s = set(b)
for i,x in enumerate(a):
if x in s:
c[i] = b.index(x)
else:
c[i] = -1
return c
def method_bisect(a,b,c):
" Finds indexes using bisection "
# Create a sorted b with its index
bsorted = sorted([(x, i) for i, x in enumerate(b)], key = lambda t: t[0])
for i,x in enumerate(a):
index = bisect.bisect_left(bsorted,(x, ))
c[i] = -1
if index < len(a):
if x == bsorted[index][0]:
c[i] = bsorted[index][1] # index in the b array
return c
def method_reverse_lookup(a, b, c):
reverse_lookup = {x:i for i, x in enumerate(b)}
for i, x in enumerate(a):
c[i] = reverse_lookup.get(x, -1)
return c
def profile():
Nls = [x for x in range(1000,20000,1000)]
number_iterations = 10
methods = [method_in, method_try, method_set_in, method_bisect, method_reverse_lookup]
time_methods = [[] for _ in range(len(methods))]
for N in Nls:
a = [x for x in range(0,N)]
random.shuffle(a)
b = [x for x in range(0,N)]
random.shuffle(b)
c = [0 for x in range(0,N)]
for i, func in enumerate(methods):
wrapped = wrapper(func, a, b, c)
time_methods[i].append(math.log(timeit.timeit(wrapped, number=number_iterations)))
markers = itertools.cycle(('o', '+', '.', '>', '2'))
colors = itertools.cycle(('r', 'b', 'g', 'y', 'c'))
labels = itertools.cycle(('in', 'try', 'set', 'bisect', 'reverse'))
for i in range(len(time_methods)):
plt.plot(Nls,time_methods[i],marker = next(markers),color=next(colors),linestyle='-',label=next(labels))
plt.xlabel('list size', fontsize=18)
plt.ylabel('log(time)', fontsize=18)
plt.legend(loc = 'upper left')
plt.show()
profile()
bisect
โมดูล