Renomearei a função take_closestpara 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.minbisect.bisect_left
O "quase" vem do fato de bisect_leftexigir 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 bisectmó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 myNumberdeve 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 myListdeve ser classificada? Digamos que classifiquemos uma cópia da lista sempre que take_closest for chamada, deixando a minsolução inalterada. Usando a lista de 200 itens no teste acima, a bisectsoluçã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 minainda 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 myListcresce em tamanho, a minsolução será eventualmente mais rápida. Observe que tivemos que empilhar tudo a seu favor para a minsolução vencer.