¿Cómo puedo ordenar los valores del mapa por clave en Java?

7 minutos de lectura

avatar de usuario de n00bstackie
n00bstackie

Tengo un mapa que tiene cadenas para claves y valores.

Los datos son como los siguientes:

“pregunta1”, “1”
“pregunta9”, “1”
“pregunta2”, “4”
“pregunta5”, “2”

Quiero ordenar el mapa según sus claves. Entonces, al final, tendré question1, question2, question3y así.

Eventualmente, estoy tratando de obtener dos cadenas de este Mapa:

  • Primera Cadena: Preguntas (en orden 1 .. 10)
  • Segunda Cadena: Respuestas (en el mismo orden que la pregunta)

Ahora mismo tengo lo siguiente:

Iterator it = paramMap.entrySet().iterator();
while (it.hasNext()) {
    Map.Entry pairs = (Map.Entry) it.next();
    questionAnswers += pairs.getKey() + ",";
}

Esto me da las preguntas en una cadena, pero no están en orden.

  • Siempre que no pueda usar TreeMap, en Java 8 podemos usar el método toMap (): stackoverflow.com/a/40649809/1216775

    – akhil_mittal

    18 de octubre de 2021 a las 4:41

Avatar de usuario de Jherico
Jherico

Respuesta corta

Utilizar una TreeMap. Esto es precisamente para lo que es.

Si se le pasa este mapa y no puede determinar el tipo, entonces puede hacer lo siguiente:

SortedSet<String> keys = new TreeSet<>(map.keySet());
for (String key : keys) { 
   String value = map.get(key);
   // do something
}

Esto iterará a través del mapa en el orden natural de las claves.


Respuesta más larga

Técnicamente, puedes usar cualquier cosa que implemente SortedMappero excepto en casos raros esto equivale a TreeMapal igual que usar un Map la implementación típicamente equivale a HashMap.

Para los casos en los que sus claves son de un tipo complejo que no implementa Comparable o no desea utilizar el orden natural, entonces TreeMap y TreeSet tienen constructores adicionales que le permiten pasar en un Comparator:

// placed inline for the demonstration, but doesn't have to be a lambda expression
Comparator<Foo> comparator = (Foo o1, Foo o2) -> {
        ...
    }

SortedSet<Foo> keys = new TreeSet<>(comparator);
keys.addAll(map.keySet());

Recuerde cuando use un TreeMap o TreeSet que tendrá diferentes características de rendimiento que HashMap o HashSet. En términos generales, las operaciones que buscan o insertan un elemento van desde O(1) a O (registro (N)).

en un HashMappasar de 1000 elementos a 10 000 realmente no afecta su tiempo para buscar un elemento, pero por un TreeMap el tiempo de búsqueda será aproximadamente 1,3 veces más lento (suponiendo que Log2). Pasar de 1000 a 100 000 será aproximadamente 1,6 veces más lento para cada búsqueda de elementos.

  • Estoy tratando de usar Treemap y ordenar las claves de cadena según la longitud. Encuentro que estoy obteniendo resultados de recuperación inconsistentes. ¿Aparentemente porque TreeMap considera un resultado de comparación de 0 como “igual”? No estoy seguro de cómo usarlo en este caso.

    – Marc

    16/08/2013 a las 16:35

  • compareTo() resultado de 0 es ‘igual’. Si está escribiendo un comparador que ordena por longitud de cadena, debe devolver un valor positivo o negativo en función de qué cadena es más larga, y solo devolver 0 si ambas cadenas tienen la misma longitud. si a y b son cadenas, puede hacer esto como `return a.length() – b.length()’ (o invertir los valores si quiere que estén ordenados en la otra dirección).

    – Jherico

    16/08/2013 a las 20:15

  • Hola chicos, si quisiera ordenar el Mapa por claves, que aquí es 1,2,3,4, ¿cuál es el orden de inserción… por qué no usamos LinkedHashSet? Simplemente ponemos las preguntas una por una, y se va ordenando por orden de inserción. ¿Puede alguien ayudarme con esto?

    – narancs

    19 de junio de 2015 a las 13:15

  • @Karoly LinkedHashSet funcionaría para recuperar los elementos en el orden en que los insertó. Lo que OP quiere es recuperar los elementos en un orden de clasificación predeterminado, independientemente del orden de inserción.

    –David Berry

    13 de noviembre de 2015 a las 16:28

  • @cricket_007 el código demuestra específicamente cómo iterar a través de las claves para un mapa que aún no está ordenado.

    – Jherico

    2 de marzo de 2016 a las 17:47

Avatar de usuario de TrayMan
TrayMan

Suponiendo que TreeMap no es bueno para usted (y suponiendo que no puede usar genéricos):

List sortedKeys=new ArrayList(yourMap.keySet());
Collections.sort(sortedKeys);
// Do what you need with sortedKeys.

  • ¡Gracias! Necesitaba hacer algo como esto ya que mis claves eran de tipo complejo.

    –Ross Hambrick

    26 de julio de 2011 a las 16:24

  • Esto solo ordenará la lista de claves, pero no ordenará el mapa en sí según las claves. También estoy buscando cómo ordenar el mapa según las claves y podría encontrar una manera. Supongo que tendré que probar con TreeMap 🙂

    – Crenguta S

    21 de noviembre de 2016 a las 12:42

  • sortedKeys.sort() funcionará bien si usa Java 8+

    – Amir Hossain

    17/04/2021 a las 19:00

  • aliciaKeys.sing();

    – Aquarelle

    28 de septiembre de 2021 a las 11:13

  • No sé por qué se votó esto, esta respuesta solo ordenará las claves, no el Mapa. Incluso si intenta crear un nuevo HashMap e insertar elementos por claves ordenadas, su nuevo HashMap NO conservará el orden de inserción.

    – Yassir Khaldi

    4 oct 2021 a las 13:34

Avatar de usuario de Manoj Singh
manoj singh

Utilizando el TreeMap puede ordenar el mapa.

Map<String, String> map = new HashMap<>();        
Map<String, String> treeMap = new TreeMap<>(map);
for (String str : treeMap.keySet()) {
    System.out.println(str);
}

  • Map> treeMap = new TreeMap>(printHashMap); for (String str : treeMap.keySet()) { System.out.println(str + ” ” + treeMap.get(str)); }

    – vikramvi

    21 ago 2016 a las 15:40


Avatar de usuario de Aliti
Aliti

Solo usa TreeMap:

new TreeMap<String, String>(unsortMap);

Tenga en cuenta que TreeMap se ordena de acuerdo con el orden natural de sus ‘claves’.

Avatar de usuario de AgileJon
AgileJon

Utilizar una ÁrbolMapa!

  • No sé Java 🙁 Esto funciona al 100%. Mucho más simple que cualquiera de las horribles soluciones que se me ocurrieron.

    – Pedro Chaula

    24 de mayo de 2020 a las 10:34


Avatar de usuario de Peter Mortensen
Pedro Mortensen

Si ya tiene un mapa y le gustaría ordenarlo por claves, simplemente use:

Map<String, String> treeMap = new TreeMap<String, String>(yourMap);

Un ejemplo de trabajo completo:

import java.util.HashMap;
import java.util.Set;
import java.util.Map;
import java.util.TreeMap;
import java.util.Iterator;

class SortOnKey {

    public static void main(String[] args) {
       HashMap<String, String> hm = new HashMap<String, String>();
       hm.put("3", "three");
       hm.put("1", "one");
       hm.put("4", "four");
       hm.put("2", "two");
       printMap(hm);
       Map<String, String> treeMap = new TreeMap<String, String>(hm);
       printMap(treeMap);
    } // main

    public static void printMap(Map<String, String> map) {
        Set s = map.entrySet();
        Iterator it = s.iterator();
        while (it.hasNext()) {
           Map.Entry entry = (Map.Entry) it.next();
           String key = (String) entry.getKey();
           String value = (String) entry.getValue();
           System.out.println(key + " => " + value);
        } // while
        System.out.println("========================");
    } // printMap

} // class

  • No sé Java 🙁 Esto funciona al 100%. Mucho más simple que cualquiera de las horribles soluciones que se me ocurrieron.

    – Pedro Chaula

    24 de mayo de 2020 a las 10:34


Avatar de usuario de Peter Mortensen
Pedro Mortensen

Siempre que no pueda usar TreeMapen Java 8 podemos hacer uso de la para asignar() método en Collectors que toma los siguientes parámetros:

  • mapeador de teclas: función de mapeo para producir claves
  • mapeador de valor: función de mapeo para producir valores
  • fusionar función: una función de combinación, utilizada para resolver colisiones entre valores asociados con la misma clave
  • mapaProveedor: una función que devuelve un Mapa nuevo y vacío en el que se insertarán los resultados.

Ejemplo de Java 8

Map<String, String> sample = new HashMap<>(); // Push some values to map
Map<String, String> newMapSortedByKey = sample.entrySet().stream()
                    .sorted(Map.Entry.<String, String>comparingByKey().reversed())
                    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
Map<String, String> newMapSortedByValue = sample.entrySet().stream()
                        .sorted(Map.Entry.<String, String>comparingByValue().reversed())
                        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));

Podemos modificar el ejemplo para usar un comparador personalizado y ordenar según las claves como:

Map<String, String> newMapSortedByKey = sample.entrySet().stream()
                .sorted((e1, e2) -> e1.getKey().compareTo(e2.getKey()))
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));

¿Ha sido útil esta solución?