2012-03-26 14 views
5

que tiene una lista de Python de enteros predefinidos:Python: Redondo al siguiente número entero predefinido en la lista

intvals = [5000, 7500, 10000, 20000, 30000, 40000, 50000] 

necesito para redondear hacia arriba y abajo a la siguiente mayor valor inferior/en la lista. Entonces, por ejemplo, dado el número 8000, el resultado debería ser [7500, 10000]. Para 42000, debe ser [40000, 50000]. Me pregunto si hay una manera fácil de hacerlo.

Mi idea sería crear una función que tenga dos bucles, uno que disminuya un valor -1 hasta que encuentre uno en la lista, y uno que aumente el valor en 1 hasta que encuentre la coincidencia más alta. Esto funcionaría, pero tal vez hay una mejor solución?

Respuesta

15

Esto es perfecto para bisect.bisect_right() y bisect.bisect_left().

Aquí es un código de ejemplo para los que se puede ampliar en:

import bisect 

def get_interval(x): 
    intvals = [5000, 7500, 10000, 20000, 30000, 40000, 50000] 
    i = bisect.bisect_right(intvals,x) 
    return intvals[i-1:i+1] 

print get_interval(5500) 

""" 
>>> 
[5000, 7500] 
""" 

Esta técnica es rápida, ya que utiliza la búsqueda binaria (por lo logN en lugar de n operaciones de búsqueda)

+0

Eso es increíble. –

+1

En particular, necesitará un código para manejar las cajas de borde (¿se define 'get_interval (5)'?) –

+0

Gracias por su rápida respuesta. ¡Exactamente lo que necesito! Nunca he oído hablar del módulo de bisección – Daniel

2

bisect está diseñado para buscar de esta manera.

>>> intvals[bisect.bisect(intvals, 8000)] 
10000 
>>> intvals[bisect.bisect(intvals, 42000)] 
50000 
5

Usted puede utilizar el módulo bisect . Puede que tenga que ajustar el ejemplo para satisfacer las necesidades de su caso límite.

>>> import bisect 
>>> def RoundUpDown(rangeList,num): 
    beg = bisect.bisect_right(rangeList,num) 
    if rangeList[beg-1] == num: #Handle Perfect Hit Edge Case 
     return [num,num] 
    elif not beg: #Left Edge Case 
     return [None,rangeList[0]] 
    elif beg == len(rangeList): #Right Edge Case 
     return [rangeList[-1],None] 
    else: 
     return rangeList[beg-1:beg+1] 


>>> RoundUpDown([5000, 7500, 10000, 20000, 30000, 40000, 50000],41000) 
[40000, 50000] 
>>> RoundUpDown([5000, 7500, 10000, 20000, 30000, 40000, 50000],5000) 
[5000, 5000] 
>>> RoundUpDown([5000, 7500, 10000, 20000, 30000, 40000, 50000],500) 
[None, 5000] 
>>> RoundUpDown([5000, 7500, 10000, 20000, 30000, 40000, 50000],50000) 
[50000, 50000] 
>>> RoundUpDown([5000, 7500, 10000, 20000, 30000, 40000, 50000],51000) 
[50000, None] 
>>> RoundUpDown([5000, 7500, 10000, 20000, 30000, 40000, 50000],7500) 
[7500, 7500] 
>>> 
0

Establezca un 'minDiff' int a maxint y un 'minIndex' en -1. Itere la lista y calcule el valor absoluto de la diferencia entre el valor de la lista indexada y el objetivo. Si este valor es menor que el minDiff, cárguelo en el minDiff y almacene el índice en minIndex. Si el valor es más que el minDiff, devuelva el minIndex. Nota: asume que la lista está ordenada. Si la lista no está ordenada, tendrá que repetir la lista completa para asegurarse de haber encontrado la diferencia mínima.

0

Si eres intervalos no son demasiado grandes y no son demasiado preocupado por el consumo de memoria, a continuación, la siguiente solución será rápida:

intvals = [5000, 7500, 10000, 20000, 30000, 40000, 50000] 

pairs = zip(intvals,intvals[1:]) 
d = {} 
for start,end in pairs: 
    for i in range(start,end+1): 
     d[i] = (start,end) 

def get_interval(i): 
    if i in d: 
     return d[i] 
    else: 
     return -1 

print get_interval(5500) 

""" 
>>> 
(5000, 7500) 
""" 

nota que no se han preocupado por lo get_interval (7500) debería regresar (aunque 7500 está en dos intervalos ...) pero puede corregirlo para que sea lo que desea.

Cuestiones relacionadas