Mappa ordinata Java


322

In Java, esiste un oggetto che agisce come una mappa per archiviare e accedere a coppie chiave / valore, ma può restituire un elenco ordinato di chiavi e un elenco ordinato di valori, in modo tale che gli elenchi chiave e valore siano nello stesso ordine?

Quindi, come spiegazione per codice, sto cercando qualcosa che si comporti come la mia mappa ordinata fittizia:

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);
}

4
Se tutto ciò che vuoi fare è scorrere entrambi contemporaneamente, Map.entrySet () ti consentirà di farlo su qualsiasi mappa. LinkedHashMap ha un ordine ben definito, ma per qualsiasi mappa l'insieme di voci riflette le coppie chiave / valore.
Pete Kirkham,

5
Questo codice non è un buon esempio in quanto qualsiasi implementazione di Map si comporterà come codice di esempio. ordinati, ordinati o no.
Peter Lawrey,

2
Nell'implementazione di Sun JDK, i set restituiti da getKeys e getValues ​​() sono supportati da entrySet () nella mappa, quindi avranno lo stesso ordine di iterazione, che è ciò che il campione prova.
Pete Kirkham,

4
Beh, è ​​interessante, non l'ho mai notato. Tuttavia, chiamami pazzo, ma preferisco non fare ipotesi sull'implementazione che non sono esplicitamente verificate dall'interfaccia. Sono stato bruciato troppe volte in passato.
Che cosa è il

2
Questo dovrebbe essere chiamato Java Sorted Map, poiché Ordered Map è qualcosa di diverso - vedi LinkedHashMap.
Ondra Žižka,

Risposte:


398

Il SortedMap di interfaccia (con l'implementazione TreeMap ) dovrebbe essere tuo amico.

L'interfaccia ha i metodi:

  • keySet() che restituisce un set di chiavi in ​​ordine crescente
  • values() che restituisce una raccolta di tutti i valori in ordine crescente delle chiavi corrispondenti

Quindi questa interfaccia soddisfa esattamente le tue esigenze. Tuttavia, le chiavi devono avere un ordine significativo. Altrimenti è possibile utilizzare LinkedHashMap in cui l'ordine è determinato dall'ordine di inserzione.


2
esempio: SortedMap <String, Object> map = new TreeMap <> ();
Ben

7
Per utilizzare TreeMap è necessario che la classe di chiavi debba implementare l'interfaccia Comparable. In caso contrario, verrà generato un tipo di RuntimeException. TreeMap è anche una mappa ordinata, ma penso che l'autore voglia usare solo una mappa ordinata (non ordinata). LinkedHashMap è una buona scelta per ottenere solo la mappa ordinata (come hai detto, "determinata dall'ordine di inserzione").
K. Gol

1
questa risposta potrebbe essere migliorata mostrando come eseguire l'iterazione su keySet ()

4
Da java 8 doc . LinkedHashMapil cui ordine di iterazione è l' ordine in cui le sue voci sono state accedute per l'ultima volta
TRiNE

1
@TRiNE Non seguo il tuo commento, ma potrei essermi perso un po 'di contesto. Per impostazione predefinita LinkedHashMap, l'ordine di iterazione è ordine di inserimento, ma è possibile utilizzare un costruttore diverso per specificare l'ordine di accesso. docs.oracle.com/javase/8/docs/api/java/util/…
rob

212

Esiste un oggetto che agisce come una mappa per memorizzare e accedere a coppie chiave / valore, ma può restituire un elenco ordinato di chiavi e un elenco ordinato di valori, in modo tale che gli elenchi chiave e valore siano nello stesso ordine?

Stai cercando java.util.LinkedHashMap . Otterrai un elenco di coppie Map.Entry <K, V> , che vengono sempre ripetute nello stesso ordine. Tale ordine è uguale all'ordine in cui si inseriscono gli articoli. In alternativa, utilizzare java.util.SortedMap , dove le chiavi devono avere un ordinamento naturale o averlo specificato da a Comparator.


14
E per salvare il lettore ricontrollandolo, poiché è difficile verificarlo testandolo, il keySet()metodo restituisce effettivamente un LinkedHashSet che riflette l'ordine delle put()chiamate. Si noti che le chiamate ripetute a put()per lo stesso tasto non cambieranno l'ordine a meno che non si preveda remove()il tasto.
Glenn Lawrence,

Da java 8 doc . LinkedHashMapil cui ordine di iterazione è l' ordine in cui le sue voci sono state accedute per l'ultima volta
TRiNE

24

LinkedHashMap mantiene l'ordine delle chiavi.

java.util.LinkedHashMap sembra funzionare come una normale HashMap altrimenti.


1
Questo non fornisce una risposta alla domanda. Per criticare o richiedere chiarimenti a un autore, lascia un commento sotto il suo post: puoi sempre commentare i tuoi post e una volta che avrai una reputazione sufficiente sarai in grado di commentare qualsiasi post .
ianaya89,

2
@ ianaya89 Penso che questa sia una vera risposta, ma è molto simile alla risposta di John Feminella !
T30

1
Se vuoi ottenere una mappa ordinata, in cui le voci sono memorizzate in quell'ordine mentre le inserisci nella mappa, allora una LinkedHashMap è la risposta giusta. Se vuoi ordinare le voci nella tua mappa indipendentemente dall'ordine in cui le hai inserite, allora una SortedMap è la risposta giusta.
Ralph,

@TRiNE Il documento java 8 che hai collegato dice che ci sono due modalità di ordinamento possibili: ordine di inserimento e ordine di accesso. Pensa a quest'ultimo che viene invocato dall'uso di uno speciale costruttore pubblico LinkedHashMap (int initialCapacity, float loadFactor, boolean accessOrder). Il costruttore predefinito crea un'istanza LinkedHashMap ordinata per inserimento.
Artur Łysik,

1
@ ArturŁysik sì, lo è. È stato un errore fatto da me giorni fa. Lo correggerò. Sto cancellando il commento. poiché non posso più modificarlo
TRiNE il

7

Penso che la raccolta più vicina che otterrai dal framework sia SortedMap


3
Voterei questa risposta se pensassi che valesse la pena perdere i punti. Come sottolinea la risposta sopra, la tua risposta manca delle informazioni corrette su LinkedHashMap e anche una piccola spiegazione di SortedMap sarebbe buona.
Coray:

@CorayThan, in quel caso hai votato le risposte migliori, non hai votato gli altri che potrebbero essere corretti ma non i migliori ...
bruno conde

1
Questo è quello che ho fatto. Solo dicendo che posso capire perché qualcuno dovrebbe votarlo.
Coray:

5

È possibile sfruttare l' interfaccia NavigableMap a cui è possibile accedere e attraversare in ordine crescente o decrescente. Questa interfaccia è destinata a sostituire l'interfaccia SortedMap. La mappa navigabile viene solitamente ordinata in base all'ordinamento naturale delle sue chiavi o da un comparatore fornito al momento della creazione della mappa.

Ci sono tre maggior parte delle implementazioni utili di esso: TreeMap , ImmutableSortedMap e ConcurrentSkipListMap .

Esempio di 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) + ")");
}

Produzione:

Alice (ID = 2)
Bob (ID = 1)
John (ID = 3)



2

tl; dr

Per mantenere Map< Integer , String >un ordine ordinato per chiave, utilizzare una delle due classi che implementano le interfacce SortedMap/ NavigableMap:

  • TreeMap
  • ConcurrentSkipListMap

Se si manipola la mappa all'interno di un singolo thread, utilizzare il primo TreeMap,. Se manipoli tra i thread, usa il secondo ConcurrentSkipListMap,.

Per i dettagli, vedere la tabella seguente e la seguente discussione.

Dettagli

Ecco una tabella grafica che ho creato che mostra le funzionalità delle dieci Mapimplementazioni in bundle con Java 11.

L' NavigableMapinterfaccia è quella che SortedMapavrebbe dovuto essere in primo luogo. Il SortedMaplogicamente dovrebbe essere rimosso ma non può essere poiché alcune implementazioni di mappe di terze parti potrebbero utilizzare l'interfaccia.

Come puoi vedere in questa tabella, solo due classi implementano le interfacce SortedMap/ NavigableMap:

Entrambi mantengono le chiavi in ​​ordine ordinato, sia per il loro ordine naturale (usando il compareTometodo del Comparable( https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/ Comparable.html )) o tramite Comparatorun'implementazione che passi. La differenza tra queste due classi è che la seconda ConcurrentSkipListMap, è thread-safe , altamente concorrenziale .

Vedi anche la colonna Ordine di iterazione nella tabella seguente.

  • La LinkedHashMapclasse restituisce le voci in base all'ordine in cui sono state inizialmente inserite .
  • EnumMaprestituisce le voci nell'ordine in cui è definita la classe enum della chiave . Ad esempio, una mappa di quale dipendente copre quale giorno della settimana ( Map< DayOfWeek , Person >) utilizza la DayOfWeekclasse enum integrata in Java. Quell'enum è definito con lunedì primo e domenica scorso. Quindi le voci in un iteratore appariranno in quell'ordine.

Le altre sei implementazioni non promettono l'ordine in cui riportano le loro voci.

Tabella delle implementazioni delle mappe in Java 11, confrontando le loro caratteristiche


0

Ho usato la mappa Hash semplice, l'elenco collegato e le raccolte per ordinare una mappa in base ai valori.

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);
     }
   }
}

L'output è:

C=0
C++=1
Java=2
Python=3
JavaScript=4
Golang=5
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.