원래 질문은 다음과 같습니다.
값이 목록 (수백만 개의 값이 포함 된 목록)에 존재하고 그 색인이 무엇인지 아는 가장 빠른 방법은 무엇입니까?
따라서 찾아야 할 두 가지가 있습니다.
- 목록의 항목이며
- 색인은 무엇입니까 (목록에있는 경우).
이를 위해 모든 경우에 인덱스를 계산하기 위해 @xslittlegrass 코드를 수정하고 추가 방법을 추가했습니다.
결과
방법은 다음과 같습니다.
- in-- 기본적으로 x in b 인 경우 : b.index (x)를 반환
- b.index (x)에서 try-try / catch (x가 b인지 확인해야 함)
- set-- 기본적으로 set (b)의 x 인 경우 : b.index (x)를 반환
- bisect-인덱스가있는 b를 정렬하고 sorted (b)에서 x를 이진 검색합니다. @xslittlegrass의 mod는 원래 b가 아닌 정렬 된 b로 인덱스를 반환합니다.
- reverse--b에 대한 역방향 조회 사전 d를 형성합니다. d [x]는 x의 인덱스를 제공합니다.
결과는 방법 5가 가장 빠르다는 것을 보여줍니다.
흥미롭게도 try 및 set 메소드는 시간이 동일합니다.
테스트 코드
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
모듈을 사용하십시오