2011-04-27 8 views
12

si tengo un diccionario como estebúsqueda de diccionario personalizado en Python

>>> d = {10: 3, 100: 2, 1000: 1} 

puedo escribir algo como:

>>> d.get(10), d.get(100), d.get(1000) 
(3, 2, 1) 

Aunque quiero que si no se encuentra la clave dada, el valor correspondiente al respeto clave más cercana se devuelve la clave dada:

>>> d.get(20), d.get(60), d.get(200) 
(3, 2, 2) 

en cambio, el resultado en Python es

(None, None, None) 

¿Cuál es una manera pitonica de implementar el comportamiento que describí?

Gracias

+2

No es un duplicado exacto, pero útil: http://stackoverflow.com/questions/2390827/how-to-properly-subclass-dict-and-override-get-set –

Respuesta

17

Puede derivar de dict para cambiar el comportamiento del método get():

class ClosestDict(dict): 
    def get(self, key): 
     key = min(self.iterkeys(), key=lambda x: abs(x - key)) 
     return dict.get(self, key) 

d = ClosestDict({10: 3, 100: 2, 1000: 1}) 
print (d.get(20), d.get(60), d.get(200)) 

impresiones

(3, 2, 2) 

Tenga en cuenta que la complejidad de get() ya no es O (1), pero O (norte).

+3

Esto hace que las operaciones de búsqueda O (n) sin embargo, así que úselo con cuidado. Tal vez deberías darle un nombre diferente en su lugar. – delnan

+0

+1: ¡Eso fue rápido, elegante y simple! –

+0

@delnan: ¿Alguna sugerencia para un buen nombre? –

6

bisect módulo permite la búsqueda rápida de la posición de inserción en una lista ordenada.

from bisect import bisect_right 

def closest_matches(data, query): 
    keys = sorted(data) 
    return [data[i] for i in (min(map(abs, (keys[p-1], keys[p]))) for p in (bisect_right(keys, k) for k in query))] 

>>> d = {10: 3, 100: 2, 1000: 1} 
>>> closest_matches(d, [20, 60, 200]) 
[3, 3, 2] 
Cuestiones relacionadas