2009-07-29 22 views
11

Estoy refactorizando una función que, dada una serie de puntos finales que implícitamente definen intervalos, comprueba si se incluye un número en el intervalo, y luego devuelve el correspondiente (no relacionado de ninguna manera computable) El código que ahora se encarga de la obra es:Python: mapeo de intervalos a valores

if p <= 100: 
    return 0 
elif p > 100 and p <= 300: 
    return 1 
elif p > 300 and p <= 500: 
    return 2 
elif p > 500 and p <= 800: 
    return 3 
elif p > 800 and p <= 1000: 
    return 4 
elif p > 1000: 
    return 5 

que es la OMI bastante horrible, y le falta en que tanto los intervalos y los valores de retorno están codificados. Cualquier uso de cualquier estructura de datos es, por supuesto, posible.

Respuesta

35
import bisect 
bisect.bisect_left([100,300,500,800,1000], p) 
+0

+1 Me gusta esto. Tu aprendes algo nuevo cada dia. – kjfletch

+0

+1: ¡increíble! –

+1

Verdaderamente impresionante. Super clean, y creo muy rápido también. También se puede extender fácilmente en caso de que uno necesite un pedido no natural u otra cosa a cambio, como una cadena: import bisect n = bisección.bisect_left ([100,300,500,800,1000], p) a = ["ausente", "bajo", "promedio", "alto", "muy alto", "extremo"] a [n] – Agos

0

Probar algo en la línea de:

d = {(None,100): 0, 
    (100,200): 1, 
    ... 
    (1000, None): 5} 
value = 300 # example value 
for k,v in d.items(): 
    if (k[0] is None or value > k[0]) and (k[1] is None or value <= k[1]): 
     return v 
3

Usted podría intentar una toma en esto:

def check_mapping(p): 
    mapping = [(100, 0), (300, 1), (500, 2)] # Add all your values and returns here 

    for check, value in mapping: 
     if p <= check: 
      return value 

print check_mapping(12) 
print check_mapping(101) 
print check_mapping(303) 

produce:

0 
1 
2 

Como siempre en Python, habrá mejores formas de hacerlo.

+0

No considera el caso de p> 1000! – stefanw

+0

Es por eso que especifiqué: "Podría intentar una versión de esto" – kjfletch

+0

. Esa última frase es irónica, considerando la filosofía de Python de tener preferiblemente solo una forma obvia de hacer algo. – sykora

0
def which_interval(endpoints, number): 
    for n, endpoint in enumerate(endpoints): 
     if number <= endpoint: 
      return n 
     previous = endpoint 
    return n + 1 

de pasar sus puntos finales como una lista en endpoints, así:

which_interval([100, 300, 500, 800, 1000], 5) 

Editar:

Lo anterior es una búsqueda lineal. La respuesta de Glenn Maynard tendrá un mejor rendimiento, ya que utiliza un algoritmo de bisección.

+0

Pierde la alcaparra "anterior"; es bastante redundante. –

+0

Sí, tienes razón, creo que el código original "me inspiró" a usarlo. Por cierto, su uso del imperativo puede sonar un poco brusco para algunos. – Steef

+0

@Steef: Quizás desee considerar una sugerencia humilde de que podría reconsiderar su respuesta en su tiempo libre, tenga en cuenta que ** su respuesta aún incluye una línea de código redundante **, y en el transcurso del tiempo, elimine la misma. –

0

Otra forma ...

def which(lst, p): 
    return len([1 for el in lst if p > el]) 

lst = [100, 300, 500, 800, 1000] 
which(lst, 2) 
which(lst, 101) 
which(lst, 1001) 
3

De hecho, es bastante horrible. Sin el requisito de no tener hardcoding, que debería haber sido escrito así:

if p <= 100: 
    return 0 
elif p <= 300: 
    return 1 
elif p <= 500: 
    return 2 
elif p <= 800: 
    return 3 
elif p <= 1000: 
    return 4 
else: 
    return 5 

Éstos son ejemplos de la creación de una función de búsqueda, tanto lineales como mediante la búsqueda binaria, con el requisito de no-hardcodings cumplido, y un par de verificaciones de cordura en las dos tablas:

def make_linear_lookup(keys, values): 
    assert sorted(keys) == keys 
    assert len(values) == len(keys) + 1 
    def f(query): 
     return values[sum(1 for key in keys if query > key)] 
    return f 

import bisect 
def make_bisect_lookup(keys, values): 
    assert sorted(keys) == keys 
    assert len(values) == len(keys) + 1 
    def f(query): 
     return values[bisect.bisect_left(keys, query)] 
    return f 
+0

Me gusta este mejor que el que tiene más votos debido a su forma más generalizada/no codificada y porque es más profunda. – JAB

Cuestiones relacionadas