Mapa ordenado de Java

322

En Java, ¿hay un objeto que actúa como un Mapa para almacenar y acceder a pares clave / valor, pero puede devolver una lista ordenada de claves y una lista ordenada de valores, de modo que las listas clave y de valores estén en el mismo orden?

Entonces, como explicación por código, estoy buscando algo que se comporte como mi OrderedMap ficticio:

OrderedMap<Integer, String> om = new OrderedMap<>();
om.put(0, "Zero");
om.put(7, "Seven");

String o = om.get(7); // o is "Seven"
List<Integer> keys = om.getKeys();
List<String> values = om.getValues();

for(int i = 0; i < keys.size(); i++)
{
    Integer key = keys.get(i);
    String value = values.get(i);
    Assert(om.get(key) == value);
}
Que es eso
fuente
44
Si todo lo que quieres hacer es iterar a través de ambos al mismo tiempo, Map.entrySet () te permitirá hacerlo en cualquier mapa. LinkedHashMap tiene un orden bien definido, pero para cualquier mapa, el conjunto de entradas refleja los pares clave / valor.
Pete Kirkham el
55
Este código no es un buen ejemplo, ya que cualquier implementación de Map se comportará como su código de muestra. ordenado, ordenado o no.
Peter Lawrey
2
En la implementación de Sun JDK, los conjuntos devueltos por getKeys y getValues ​​() están respaldados por entrySet () en el mapa, por lo que tendrán el mismo orden de iteración, que es lo que prueban sus muestras.
Pete Kirkham
44
Bueno, eso es interesante, nunca me di cuenta de eso. Aún así, llámame loco, pero prefiero no hacer suposiciones sobre la implementación que la interfaz no verifique explícitamente. Me quemé muchas veces haciendo eso en el pasado.
Whatsit
2
Esto debería llamarse Mapa ordenado de Java, ya que el Mapa ordenado es algo diferente, vea LinkedHashMap.
Ondra Žižka

Respuestas:

398

La interfaz SortedMap (con la implementación TreeMap ) debería ser tu amiga.

La interfaz tiene los métodos:

  • keySet() que devuelve un conjunto de claves en orden ascendente
  • values() que devuelve una colección de todos los valores en el orden ascendente de las claves correspondientes

Entonces, esta interfaz cumple exactamente sus requisitos. Sin embargo, las claves deben tener un orden significativo. De lo contrario, puede usar LinkedHashMap donde el orden está determinado por el orden de inserción.

dmeister
fuente
2
ejemplo: SortedMap <String, Object> map = new TreeMap <> ();
Ben
77
Para usar TreeMap se requería que la clase clave tuviera que implementar una interfaz comparable. Si no, se lanzará algún tipo de RuntimeException. TreeMap también es un mapa ordenado, pero creo que el autor quiere usar un mapa ordenado (no ordenado). LinkedHashMap es una buena opción para obtener solo el mapa ordenado (como Usted dijo, "determinado por el orden de inserción").
K. Gol
1
esta respuesta podría mejorarse mostrando cómo iterar sobre keySet ()
44
De java 8 doc . LinkedHashMapcuyo orden de iteración es el orden en el que se accedió por última vez a sus entradas
TRiNE
1
@TRiNE No sigo tu comentario, pero es posible que me haya perdido algo de contexto. Por defecto LinkedHashMap, el orden de iteración es el orden de inserción, pero puede usar un constructor diferente para especificar el orden de acceso. docs.oracle.com/javase/8/docs/api/java/util/…
robar el
212

¿Hay un objeto que actúa como un Mapa para almacenar y acceder a pares clave / valor, pero puede devolver una lista ordenada de claves y una lista ordenada de valores, de modo que las listas clave y de valores estén en el mismo orden?

Estás buscando java.util.LinkedHashMap . Obtendrá una lista de pares Map.Entry <K, V> , que siempre se iteran en el mismo orden. Ese orden es el mismo por el que coloca los elementos. Alternativamente, use java.util.SortedMap , donde las claves deben tener un orden natural o tenerlo especificado por a Comparator.

John Feminella
fuente
14
Y para evitar que el lector keySet()vuelva a verificar esto, porque es difícil de verificar mediante pruebas, el método devuelve efectivamente un LinkedHashSet que refleja el orden de sus put()llamadas. Tenga en cuenta que las llamadas repetidas a put()la misma clave no cambiarán el orden a menos que usted remove()la clave de antemano.
Glenn Lawrence
De java 8 doc . LinkedHashMapcuyo orden de iteración es el orden en el que se accedió por última vez a sus entradas
TRiNE
24

LinkedHashMap mantiene el orden de las claves.

java.util.LinkedHashMap parece funcionar como un HashMap normal de lo contrario.

VoNWooDSoN
fuente
1
Esto no proporciona una respuesta a la pregunta. Para criticar o solicitar una aclaración de un autor, deje un comentario debajo de su publicación: siempre puede comentar sus propias publicaciones, y una vez que tenga suficiente reputación podrá comentar cualquier publicación .
ianaya89
2
@ ianaya89 Creo que esta es una respuesta real, ¡pero es muy similar a la respuesta de John Feminella !
T30
1
Si desea obtener un mapa ordenado, donde las entradas se almacenan en ese orden a medida que las coloca en el mapa, entonces LinkedHashMap es la respuesta correcta. Si desea ordenar las entradas en su mapa de forma independiente en el orden en que las colocó, entonces SortedMap es la respuesta correcta.
Ralph
@TRiNE El documento de Java 8 que vinculó dice que hay dos modos de orden posibles: orden de inserción y orden de acceso. Piensa en lo último que se invoca mediante el uso de un constructor especial public LinkedHashMap (int initialCapacity, float loadFactor, boolean accessOrder). El constructor predeterminado crea una instancia de LinkedHashMap ordenada por inserción.
Artur Łysik
1
@ ArturŁysik sí lo es. Fue un error cometido por mí hace días. Lo corregiré Estoy borrando el comentario. como ya no puedo editarlo
TRiNE
7

Creo que la colección más cercana que obtendrás del framework es SortedMap

bruno conde
fuente
3
Votaría esta respuesta si pensara que valía la pena perder los puntos por ello. Como señala la respuesta anterior, su respuesta carece de la información adecuada sobre LinkedHashMap, y una pequeña explicación de SortedMap también sería buena.
CorayThan
@CorayThan, en ese caso Upvote las mejores respuestas, otros no Downvote que pueden ser correctos pero no el mejor ...
Bruno Conde
1
Eso fue lo que hice. Solo digo que puedo entender por qué alguien lo rechazaría.
CorayThan
5

Puede aprovechar la interfaz NavigableMap a la que se puede acceder y atravesar en orden ascendente o descendente. Esta interfaz está diseñada para reemplazar la interfaz SortedMap. El mapa navegable generalmente se ordena de acuerdo con el orden natural de sus teclas, o por un comparador proporcionado en el momento de la creación del mapa.

Hay tres mayoría de las implementaciones útiles de la misma: TreeMap , ImmutableSortedMap y ConcurrentSkipListMap .

Ejemplo de TreeMap:

TreeMap<String, Integer> users = new TreeMap<String, Integer>();
users.put("Bob", 1);
users.put("Alice", 2);
users.put("John", 3);

for (String key: users.keySet()) {
  System.out.println(key + " (ID = "+ users.get(key) + ")");
}

Salida:

Alice (ID = 2)
Bob (ID = 1)
John (ID = 3)
Vitalii Fedorenko
fuente
2

tl; dr

Para mantener Map< Integer , String >un orden ordenado por clave, use cualquiera de las dos clases que implementan las interfaces SortedMap/ NavigableMap:

  • TreeMap
  • ConcurrentSkipListMap

Si manipula el mapa dentro de un solo hilo, use el primero TreeMap,. Si manipula a través de hilos, use el segundo,ConcurrentSkipListMap ,.

Para más detalles, consulte la tabla a continuación y la siguiente discusión.

Detalles

Aquí hay una tabla gráfica que hice mostrando las características de los diez Map implementaciones incluidas con Java 11.

La NavigableMapinterfaz es lo que SortedMapdebería haber sido en primer lugar. losSortedMap lógica debe ser retirado, pero no puede ser tan algunas implementaciones mapa tercera partes pueden estar usando la interfaz.

Como puede ver en esta tabla, solo dos clases implementan las interfaces SortedMap/ NavigableMap:

Ambos mantienen las claves en orden, ya sea por su orden natural (utilizando el compareTométodo de Comparable( https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/ Comparable.html ) interfaz) o por una Comparatorimplementación que pasa. La diferencia entre estas dos clases es que la segunda ConcurrentSkipListMapes segura para subprocesos , altamente concurrente .

Consulte también la columna Orden de iteración en la tabla a continuación.

  • La LinkedHashMapclase devuelve sus entradas por el orden en que se insertaron originalmente .
  • EnumMapdevuelve entradas en el orden en que se define la clase enum de la clave . Por ejemplo, un mapa de qué empleado cubre qué día de la semana ( Map< DayOfWeek , Person >) usa la DayOfWeekclase enum integrada en Java. Esa enumeración se define con el lunes primero y el domingo pasado. Entonces las entradas en un iterador aparecerán en ese orden.

Las otras seis implementaciones no prometen el orden en que informan sus entradas.

Tabla de implementaciones de mapas en Java 11, comparando sus características

Albahaca Bourque
fuente
0

He usado el mapa Simple Hash, la lista vinculada y las Colecciones para ordenar un Mapa por valores.

import java.util.*;
import java.util.Map.*;
public class Solution {

    public static void main(String[] args) {
        // create a simple hash map and insert some key-value pairs into it
        Map<String, Integer> map = new HashMap<String, Integer>();
        map.put("Python", 3);
        map.put("C", 0);
        map.put("JavaScript", 4);
        map.put("C++", 1);
        map.put("Golang", 5);
        map.put("Java", 2);
        // Create a linked list from the above map entries
        List<Entry<String, Integer>> list = new LinkedList<Entry<String, Integer>>(map.entrySet());
        // sort the linked list using Collections.sort()
        Collections.sort(list, new Comparator<Entry<String, Integer>>(){
        @Override
         public int compare(Entry<String, Integer> m1, Entry<String, Integer> m2) {
        return m1.getValue().compareTo(m2.getValue());
        }
      });
      for(Entry<String, Integer> value: list) {
         System.out.println(value);
     }
   }
}

El resultado es:

C=0
C++=1
Java=2
Python=3
JavaScript=4
Golang=5
Steffi Keran Rani J
fuente