Renomearei a função take_closest
para estar em conformidade com as convenções de nomenclatura do PEP8.
Se você quer dizer execução rápida, em vez de gravação rápida, nãomin
deve ser sua arma preferida, exceto em um caso de uso muito restrito. A solução precisa examinar todos os números da lista e fazer um cálculo para cada número. O uso é quase sempre mais rápido.min
bisect.bisect_left
O "quase" vem do fato de bisect_left
exigir que a lista seja classificada para funcionar. Felizmente, seu caso de uso é tal que você pode classificar a lista uma vez e depois deixá-la em paz. Mesmo se não, contanto que você não precise classificar antes de cada vez que ligar take_closest
, o bisect
módulo provavelmente sairá por cima. Se você estiver em dúvida, tente os dois e veja a diferença no mundo real.
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
O Bisect trabalha repetidamente pela metade uma lista e descobre em que metade myNumber
deve constar, olhando o valor médio. Isso significa que ele tem um tempo de execução de O (log n) em oposição ao tempo de execução de O (n) da resposta mais votada . Se compararmos os dois métodos e fornecermos ambos com uma ordenada myList
, estes são os resultados:
$ python -m timeit -s "
da importação mais próxima take_closest
de importação aleatória aleatória
a = intervalo (-1000, 1000, 10) "" take_closest (a, randint (-1100, 1100)) ""
100000 loops, o melhor de 3: 2,22 usec por loop
$ python -m timeit -s "
da importação mais próxima com_min
de importação aleatória aleatória
a = intervalo (-1000, 1000, 10) "" com_min (a, randint (-1100, 1100)) ""
10000 loops, o melhor de 3: 43,9 usec por loop
Portanto, neste teste em particular, bisect
é quase 20 vezes mais rápido. Para listas mais longas, a diferença será maior.
E se nivelarmos o campo de jogo removendo a pré-condição que myList
deve ser classificada? Digamos que classifiquemos uma cópia da lista sempre que take_closest
for chamada, deixando a min
solução inalterada. Usando a lista de 200 itens no teste acima, a bisect
solução ainda é a mais rápida, embora apenas em cerca de 30%.
Esse é um resultado estranho, considerando que a etapa de classificação é O (n log (n)) ! O único motivo que min
ainda está perdendo é que a classificação é feita em código c altamente otimizado, enquanto min
é necessário chamar uma função lambda para cada item. À medida que myList
cresce em tamanho, a min
solução será eventualmente mais rápida. Observe que tivemos que empilhar tudo a seu favor para a min
solução vencer.