Quiero escribir un comparador que me permita ordenar un TreeMap por valor en lugar del orden natural predeterminado.
Intenté algo como esto, pero no puedo descubrir qué salió mal:
import java.util.*;
class treeMap {
public static void main(String[] args) {
System.out.println("the main");
byValue cmp = new byValue();
Map<String, Integer> map = new TreeMap<String, Integer>(cmp);
map.put("de",10);
map.put("ab", 20);
map.put("a",5);
for (Map.Entry<String,Integer> pair: map.entrySet()) {
System.out.println(pair.getKey()+":"+pair.getValue());
}
}
}
class byValue implements Comparator<Map.Entry<String,Integer>> {
public int compare(Map.Entry<String,Integer> e1, Map.Entry<String,Integer> e2) {
if (e1.getValue() < e2.getValue()){
return 1;
} else if (e1.getValue() == e2.getValue()) {
return 0;
} else {
return -1;
}
}
}
Supongo que lo que estoy preguntando es: ¿puedo Map.Entry
pasarle al comparador?
Respuestas:
No puede
TreeMap
ordenar los valores por sí mismo, ya que eso desafía laSortedMap
especificación:Sin embargo, utilizando una colección externa, siempre puede ordenar
Map.entrySet()
como lo desee, ya sea por claves, valores o incluso una combinación (!!) de los dos.Aquí hay un método genérico que devuelve un
SortedSet
deMap.Entry
, dado unMap
cuyos valores sonComparable
:Ahora puedes hacer lo siguiente:
Tenga en cuenta que sucederán cosas funky si intenta modificar el
SortedSet
propio o elMap.Entry
interior, porque esto ya no es una "vista" del mapa original comoentrySet()
es.En términos generales, la necesidad de ordenar las entradas de un mapa por sus valores es atípica.
Nota sobre
==
paraInteger
Su comparador original se compara
Integer
usando==
. Esto casi siempre está mal, ya que==
con losInteger
operandos es una igualdad de referencia, no una igualdad de valores.Preguntas relacionadas
new Integer(i) == i
en Java? (¡¡¡SI!!!)fuente
La respuesta de polygenelubricants es casi perfecta. Sin embargo, tiene un error importante. No manejará las entradas del mapa donde los valores son los mismos.
Este código: ...
Daría salida:
Observe cómo nuestra vaca desapareció al compartir el valor "1" con nuestro mono: ¡O!
Esta modificación del código resuelve ese problema:
fuente
Set
implementación contiene un elemento más de una vez. Acabas de violar esa restricción. A partir de laSortedSet
API: Tenga en cuenta que el orden mantenido por un conjunto ordenado debe ser consistente con los iguales ... . La solución sería cambiar a unaList
implementación.Set
s aquí. ¡Ya queComparator
viola elSet
contratoSet.remove
,Set.contains
etc. no funciona ! Mira este ejemplo en ideone .int res= e1.getValue().compareTo(e2.getValue());
aint res= e2.getValue().compareTo(e1.getValue());
, tiene un orden de valores descendente en lugar de ascendente.res != 0 ? res : e1.getKey().compareTo(e2.getKey())
a preservar el orden de las teclas con valores iguales.En Java 8:
fuente
A siempre
TreeMap
está ordenado por las teclas, cualquier otra cosa es imposible. A simplemente le permite controlar cómo se ordenan las claves.Comparator
Si desea los valores ordenados, debe extraerlos en
List
ay ordenarlos.fuente
Esto no se puede hacer usando a
Comparator
, ya que siempre obtendrá la clave del mapa para comparar.TreeMap
solo se puede ordenar por clave.fuente
SortedMap
cual se especifica la clasificación por claves) beginnersbook.com/2014/07/…Comparator
usa un mapa existente para obtener los valores para ordenar. En otras palabras, no puede ordenar los valores arbitrarios puestosTreeMap
más adelante, solo los valores que ya están en el Mapa original.La respuesta de Olof es buena, pero necesita una cosa más antes de que sea perfecta. En los comentarios debajo de su respuesta, dacwe (correctamente) señala que su implementación viola el contrato Comparar / Igual para Conjuntos. Si intenta llamar a las entradas que contiene o elimina en una entrada que está claramente en el conjunto, el conjunto no lo reconocerá debido al código que permite colocar entradas con valores iguales en el conjunto. Entonces, para solucionar esto, necesitamos probar la igualdad entre las teclas:
"Tenga en cuenta que la ordenación mantenida por un conjunto ordenado (se proporcione o no un comparador explícito) debe ser coherente con iguales si el conjunto ordenado implementa correctamente la interfaz Establecer ... la interfaz Establecer se define en términos de la operación igual , pero un conjunto ordenado realiza todas las comparaciones de elementos utilizando su método compareTo (o compare), por lo que dos elementos que se consideran iguales por este método son, desde el punto de vista del conjunto ordenado, iguales ". ( http://docs.oracle.com/javase/6/docs/api/java/util/SortedSet.html )
Como originalmente pasamos por alto la igualdad para forzar al conjunto a agregar entradas de igual valor, ahora tenemos que probar la igualdad en las claves para que el conjunto realmente devuelva la entrada que está buscando. Esto es un poco desordenado y definitivamente no es cómo se pretendía usar los conjuntos, pero funciona.
fuente
Sé que esta publicación solicita específicamente ordenar un TreeMap por valores, pero para aquellos de nosotros que realmente no nos importa la implementación, pero queremos una solución que mantenga la colección ordenada a medida que se agregan elementos, agradecería sus comentarios sobre este basado en TreeSet solución. Por un lado, los elementos no se recuperan fácilmente por clave, pero para el caso de uso que tenía a mano (encontrar las n claves con los valores más bajos), esto no era un requisito.
fuente
Mucha gente escucha consejos para usar List y prefiero usarlo también
Aquí hay dos métodos que necesita para ordenar las entradas del Mapa de acuerdo con sus valores.
fuente