2009-12-30 12 views
9

Para el mapa ordenado de clojure, ¿cómo puedo encontrar la entrada que tiene la clave más cercana a un valor dado?Encontrar las teclas más cercanas a un valor dado para los mapas clasificados de Clojure

p. Ej. Supongamos que tengo

(def my-map (sorted-map 
         1 A 
         2 B 
         5 C)) 

me gustaría una función como

(find-closest my-map 4) 

que volver (5, C), ya que es la entrada con la tecla más cercano. Podría hacer una búsqueda lineal, pero dado que el mapa está ordenado, debería haber una manera de encontrar este valor en algo como O (log n).

No puedo encontrar nada en la API que lo haga posible. Si, por ejemplo, pudiera solicitar la entrada número i en el mapa, podría improvisar una función como la que yo quiero, pero no puedo encontrar ninguna de esas funciones.

Editar:

Por tanto, aparentemente ordenados-mapa se basa en una clase PersistentTreeMap implementado en Java, que es un árbol de color rojo y negro. Así que esto realmente parece que debería ser factible, al menos en principio.

Respuesta

12

subseq y rsubseq son muy rápidos porque explotan la estructura de árbol:

(def m (sorted-map 1 :a, 2 :b, 5 :c)) 

(defn abs [x] (if (neg? x) (- x) x)) 
(defn find-closest [sm k] 
    (if-let [a (key (first (rsubseq sm <= k)))] 
    (if (= a k) 
     a 
     (if-let [b (key (first (subseq sm >= k)))] 
     (if (< (abs (- k b)) (abs (- k a))) 
      b 
      a))) 
    (key (first (subseq sm >= k))))) 

user=> (find-closest m 4) 
5 
user=> (find-closest m 3) 
2 

Esto lo hace un poco más de trabajo que ideal, en el escenario ideal nos acaba de hacer una < = búsqueda a continuación, busque en el nodo de el derecho de verificar si hay algo más cerca en esa dirección. Puede acceder al árbol (.tree m) pero los métodos .left y .right no son públicos, por lo que no es posible realizar un recorrido personalizado.

+0

+1. Gracias, eso es muy útil. –

0

Lo primero que me viene a la mente es sacar las claves del mapa en un vector y luego hacer una búsqueda binaria en eso. Si no hay una coincidencia exacta con su clave, los dos punteros implicados en una búsqueda binaria terminarán apuntando a los dos elementos a cada lado, y luego puede elegir el más cercano en una sola operación (posiblemente de desempate).

+0

Desde el mapa ya está ordenado, que (esperemos) no deberían tener que tirar de todas las llaves del mapa. –

+0

de acuerdo; pero no veo otra forma de obtener acceso aleatorio a las claves. Si realiza una búsqueda secuencial, en promedio debe comparar el 50% de las claves, mientras que mi solución requiere copiar al 100%, es horrible, y ENTONCES una búsqueda de log2 (n). Mi solución solo es buena si realizarás varias de esas búsquedas con la misma información. Tal vez alguien más inteligente aparecerá y publicará una solución que nos sorprenderá a todos. –

Cuestiones relacionadas