2010-08-19 40 views
19

Supongamos que tengo un mapa en Java que se parece a esto:Obtener valores de claves dentro de un rango en Java

{ 
39:"39 to 41", 
41:"41 to 43", 
43:"43 to 45", 
45:">=45" 
} 

Si las llaves están en el orden establecido (ya sea usando mapa de árbol o LinkedHashMap) .Ahora si intento para obtener un valor que es> = 39 y < 41. Luego debería obtener la cadena "39 a 41". ¿Cómo hago esto de manera eficiente?

+0

Quieres decir '<= 41 'Supongo. ¿Pero siempre buscará '39,41,43,45' o debería funcionar si lo intenta con ex' 40,42,50'? ¿Y siempre hay solo uno en el medio? –

+0

Posible duplicado de [Estructuras de datos que pueden asignar un rango de claves a un valor] (https://stackoverflow.com/questions/13399821/data-structures-that-can-map-a-range-of-keys-to -a-value) – Vadzim

Respuesta

52

Parece que quiere más de SortedMap; ¡quieres un NavigableMap! Específicamente puede usar la operación floorKey.

He aquí un ejemplo:

NavigableMap<Integer,String> map = 
     new TreeMap<Integer, String>(); 

    map.put(0, "Kid"); 
    map.put(11, "Teens"); 
    map.put(20, "Twenties"); 
    map.put(30, "Thirties"); 
    map.put(40, "Forties"); 
    map.put(50, "Senior"); 
    map.put(100, "OMG OMG OMG!"); 

    System.out.println(map.get(map.floorKey(13)));  // Teens 
    System.out.println(map.get(map.floorKey(29)));  // Twenties 
    System.out.println(map.get(map.floorKey(30)));  // Thirties 
    System.out.println(map.floorEntry(42).getValue()); // Forties 
    System.out.println(map.get(map.floorKey(666))); // OMG OMG OMG! 

Tenga en cuenta que también hay ceilingKey, lowerKey, higherKey, y también …Entry en lugar de …Key operaciones, así que devuelve un Map.Entry<K,V> lugar de sólo el K.

+2

No lo sabía, y al parecer ninguno de los presentes tampoco. ¡Muy genial! –

+3

¡Todos saluden el tiempo de ejecución estándar! –

+1

A veces siento que conozco Java, y luego me encuentro con algo así y mi mente se deslumbra. – Jyro117

0

No estoy seguro de que sea fácil. Una sugerencia sería "rellenar los huecos", es decir, poner un valor 40->"39 to 41", etc. Supongo que eso solo será posible si conoce el rango completo de números posible en el mapa.

O mabybe algo que anula el get para verificar si el valor está en el mapa y expandirlo hasta que encuentre algo. No estoy seguro de que sea posible en su forma actual, ya que tendrías que terminar analizando las cadenas de valor.

0

Puede buscar recursivamente un límite inferior.

public String descriptionFor(int value) { 
    String description = map.get(value); 
    return description == null ? descriptionFor(value--) : description; 
} 

Deberá tener un límite mínimo.

1

Con un mapa ordenada, se podría hacer algo así:

SortedMap<Integer,String> head = map.headMap(value+1); 
if (head.isEmpty()) { 
    return null; 
} else { 
    return head.get(head.lastKey()); 
} 
0

Habría que poner en práctica dicho mapa a sí mismo, creo. Tienes razón en que debería ser ordenado; la implementación de get tendría que iterar a través de las claves hasta que encuentre la clave más grande que sea menor o igual que el argumento.

Si la subclase TreeMap inicialmente parece que puede hacer que esto funcione simplemente anulando el método get(). Sin embargo, para mantener la mayor cantidad posible del contrato de Map, tendrá que anular otros métodos para mantener la coherencia.

¿Y qué tal, p. containsKey()? ¿Su main contiene un mapeo para 40? Si devuelve false, un cliente puede decidir no llamar al get() basándose en esta información; por estos motivos (y la definición formal) debe devolver true. Pero luego hace que sea difícil determinar si el mapa "realmente contiene" un mapeo dado; si está buscando hacer algo como actualizar sin sobrescribir nada que ya exista.

El método remove() también puede ser complicado. De mi lectura de la interfaz,

// Calling map.remove "Removes the mapping for a key from this map if it is present." 
map.remove(x); 

// Now that the mapping is removed, I believe the following must hold 
assert map.get(x) == null; 
assert map.containsKey(x); 

Actuando consistentemente aquí sería muy complicado. Si tiene un mapeo de 35-40 por ejemplo, y llama al remove(38), entonces, según tengo entendido, tendrá que devolver null para cualquier obtención posterior de la clave 38, pero devuelva el mapeo antes mencionado para las claves 35-37 o 39. -40.


Así, mientras que usted puede hacer un comienzo en esta reemplazando TreeMap, tal vez todo el concepto de Map no es exactamente lo que usted quiere aquí. A menos que necesite este comportamiento para insertar en los métodos existentes que toman Map, podría ser más fácil crearlo usted mismo como una clase distinta ya que no es un Mapa, la forma en que lo está definiendo.

Cuestiones relacionadas