java - values - mkyong iterate map




Come iterare in modo efficiente su ogni voce in una mappa Java? (20)

Lambda Expression Java 8

In Java 1.8 (Java 8) questo è diventato molto più semplice utilizzando il metodo forOach dalle operazioni di aggregazione ( operazioni di flusso ) che sembra simile agli iteratori di Iterable Interface.

Basta copiare incolla sotto istruzione al tuo codice e rinominare la variabile HashMap da hm alla tua variabile HashMap per stampare la coppia chiave-valore.

HashMap<Integer,Integer> hm = new HashMap<Integer, Integer>();
/*
 *     Logic to put the Key,Value pair in your HashMap hm
 */

// Print the key value pair in one line.

hm.forEach((k,v) -> System.out.println("key: "+k+" value:"+v));

// Just copy and paste above line to your code.

Di seguito è riportato il codice di esempio che ho provato a utilizzare Lambda Expression . Questa roba è così bella. Bisogna provare.

HashMap<Integer,Integer> hm = new HashMap<Integer, Integer>();
    Random rand = new Random(47);
    int i=0;
    while(i<5){
        i++;
        int key = rand.nextInt(20);
        int value = rand.nextInt(50);
        System.out.println("Inserting key: "+key+" Value: "+value);
        Integer imap =hm.put(key,value);
        if( imap == null){
            System.out.println("Inserted");
        }
        else{
            System.out.println("Replaced with "+imap);
        }               
    }

    hm.forEach((k,v) -> System.out.println("key: "+k+" value:"+v));

Output:

Inserting key: 18 Value: 5
Inserted
Inserting key: 13 Value: 11
Inserted
Inserting key: 1 Value: 29
Inserted
Inserting key: 8 Value: 0
Inserted
Inserting key: 2 Value: 7
Inserted
key: 1 value:29
key: 18 value:5
key: 2 value:7
key: 8 value:0
key: 13 value:11

Inoltre si può usare Spliterator per lo stesso.

Spliterator sit = hm.entrySet().spliterator();

AGGIORNARE

Inclusi collegamenti alla documentazione di Oracle Docs. Per ulteriori informazioni su Lambda, vai a questo link e devi leggere le operazioni di aggregazione e per Spliterator andare a questo link .

Se ho un oggetto che implementa l'interfaccia Map in Java e desidero iterare su ogni coppia contenuta al suo interno, qual è il modo più efficiente di attraversare la mappa?

L'ordine degli elementi dipende dalla specifica implementazione della mappa che ho per l'interfaccia?


Ci sono molti modi per farlo. Di seguito sono riportati alcuni semplici passaggi:

Supponiamo di avere una mappa come:

Map<String, Integer> m = new HashMap<String, Integer>();

Quindi puoi fare qualcosa come il seguito per scorrere gli elementi della mappa.

// ********** Using an iterator ****************
Iterator<Entry<String, Integer>> me = m.entrySet().iterator();
while(me.hasNext()){
    Entry<String, Integer> pair = me.next();
    System.out.println(pair.getKey() + ":" + pair.getValue());
}

// *********** Using foreach ************************
for(Entry<String, Integer> me : m.entrySet()){
    System.out.println(me.getKey() + " : " + me.getValue());
}

// *********** Using keySet *****************************
for(String s : m.keySet()){
    System.out.println(s + " : " + m.get(s));
}

// *********** Using keySet and iterator *****************
Iterator<String> me = m.keySet().iterator();
while(me.hasNext()){
    String key = me.next();
    System.out.println(key + " : " + m.get(key));
}

Con le raccolte Eclipse (in precedenza raccolte GS ), si utilizzava il metodo MapIterable sull'interfaccia MapIterable , che viene ereditata dalle interfacce MutableMap e ImmutableMap e dalle relative implementazioni.

final MutableBag<String> result = Bags.mutable.empty();
MutableMap<Integer, String> map = Maps.mutable.of(1, "One", 2, "Two", 3, "Three");
map.forEachKeyValue(new Procedure2<Integer, String>()
{
    public void value(Integer key, String value)
    {
        result.add(key + value);
    }
});
Assert.assertEquals(Bags.mutable.of("1One", "2Two", "3Three"), result);

Con la sintassi lambda Java 8, puoi scrivere il codice come segue:

MutableBag<String> result = Bags.mutable.empty();
MutableMap<Integer, String> map = Maps.mutable.of(1, "One", 2, "Two", 3, "Three");
map.forEachKeyValue((key, value) -> result.add(key + value));
Assert.assertEquals(Bags.mutable.of("1One", "2Two", "3Three"), result);

Nota: sono un committer per le raccolte di Eclipse.


Cordiali saluti, puoi anche usare map.keySet() e map.values() se ti interessano solo le chiavi / i valori della mappa e non l'altra.


Esistono diversi modi per iterare sulla mappa.

Ecco un confronto delle loro prestazioni per un insieme di dati comuni memorizzati nella mappa memorizzando un milione di coppie di valori chiave nella mappa e itererà sulla mappa.

1) Usando entrySet() in per ogni ciclo

for (Map.Entry<String,Integer> entry : testMap.entrySet()) {
    entry.getKey();
    entry.getValue();
}

50 millisecondi

2) Utilizzo di keySet() in per ogni ciclo

for (String key : testMap.keySet()) {
    testMap.get(key);
}

76 millisecondi

3) Utilizzo di entrySet() e iteratore

Iterator<Map.Entry<String,Integer>> itr1 = testMap.entrySet().iterator();
while(itr1.hasNext()) {
    Map.Entry<String,Integer> entry = itr1.next();
    entry.getKey();
    entry.getValue();
}

50 millisecondi

4) Utilizzo di keySet() e iteratore

Iterator itr2 = testMap.keySet().iterator();
while(itr2.hasNext()) {
    String key = itr2.next();
    testMap.get(key);
}

75 millisecondi

Ho fatto riferimento a this link .


Il codice tipico per iterare su una mappa è:

Map<String,Thing> map = ...;
for (Map.Entry<String,Thing> entry : map.entrySet()) {
    String key = entry.getKey();
    Thing thing = entry.getValue();
    ...
}

HashMap è l'implementazione della mappa canonica e non fornisce garanzie (o anche se non dovrebbe cambiare ordine se non viene eseguita alcuna operazione di mutamento). SortedMap restituirà le voci in base all'ordinamento naturale delle chiavi o a un Comparator , se fornito. LinkedHashMap restituirà le voci nell'ordine di inserzione o nell'ordine di accesso a seconda di come è stato costruito. EnumMap restituisce le voci nell'ordine naturale delle chiavi.

(Aggiornamento: penso che questo non sia più vero. ) Nota, IdentityHashMap entrySet iterator attualmente ha un'implementazione particolare che restituisce la stessa istanza di Map.Entry per ogni elemento nel entrySet ! Tuttavia, ogni volta che un nuovo iteratore avanza, Map.Entry viene aggiornato.


In Java 8 abbiamo ottenuto il forEach che accetta link . Abbiamo anche le API del stream . Considera una mappa:

Map<String,String> sample = new HashMap<>();
sample.put("A","Apple");
sample.put("B", "Ball");

Iterare sui tasti:

sample.keySet().forEach((k) -> System.out.println(k));

Iterare sui valori:

sample.values().forEach((v) -> System.out.println(v));

Iterate su voci (utilizzando forEach e Stream):

sample.forEach((k,v) -> System.out.println(k + "=" + v)); 
sample.entrySet().stream().forEach((entry) -> {
            Object currentKey = entry.getKey();
            Object currentValue = entry.getValue();
            System.out.println(currentKey + "=" + currentValue);
        });

Il vantaggio con i flussi è che possono essere parallelizzati facilmente nel caso in cui lo desideriamo. Abbiamo semplicemente bisogno di usare parallelStream() al posto di stream() sopra.


In Java 8 puoi farlo in modo pulito e veloce usando le nuove funzionalità di lambdas:

 Map<String,String> map = new HashMap<>();
 map.put("SomeKey", "SomeValue");
 map.forEach( (k,v) -> [do something with key and value] );

 // such as
 map.forEach( (k,v) -> System.out.println("Key: " + k + ": Value: " + v));

Il tipo di k e v sarà dedotto dal compilatore e non è più necessario utilizzare Map.Entry .

Vai tranquillo!


In teoria, il modo più efficiente dipenderà dall'implementazione di Map. Il modo ufficiale per farlo è chiamare map.entrySet() , che restituisce un set di Map.Entry , ognuno dei quali contiene una chiave e un valore ( entry.getKey() e entry.getValue() ).

In un'implementazione idiosincratica, potrebbe fare la differenza se si utilizza map.keySet() , map.entrySet() o qualcos'altro. Ma non riesco a pensare a una ragione per cui qualcuno lo scriverebbe così. Molto probabilmente non fa differenza per le prestazioni quello che fai.

E sì, l'ordine dipenderà dall'implementazione - oltre che (eventualmente) dall'ordine di inserimento e da altri fattori difficili da controllare.

[modifica] Ho scritto valueSet() origine ma ovviamente entrySet() è in realtà la risposta.


L'ordine dipenderà sempre dalla specifica implementazione della mappa. Usando Java 8 puoi usare uno di questi:

map.forEach((k,v) -> { System.out.println(k + ":" + v); });

O:

map.entrySet().forEach((e) -> {
            System.out.println(e.getKey() + " : " + e.getValue());
        });

Il risultato sarà lo stesso (stesso ordine). Il set di voci supportato dalla mappa in modo da ottenere lo stesso ordine. Il secondo è utile in quanto consente di utilizzare lambda, ad esempio se si desidera stampare solo oggetti interi superiori a 5:

map.entrySet()
    .stream()
    .filter(e-> e.getValue() > 5)
    .forEach(System.out::println);

Il codice seguente mostra l'iterazione tramite LinkedHashMap e la normale HashMap (esempio). Vedrai la differenza nell'ordine:

public class HMIteration {


    public static void main(String[] args) {
        Map<Object, Object> linkedHashMap = new LinkedHashMap<>();
        Map<Object, Object> hashMap = new HashMap<>();

        for (int i=10; i>=0; i--) {
            linkedHashMap.put(i, i);
            hashMap.put(i, i);
        }

        System.out.println("LinkedHashMap (1): ");
        linkedHashMap.forEach((k,v) -> { System.out.print(k + " (#="+k.hashCode() + "):" + v + ", "); });

        System.out.println("\nLinkedHashMap (2): ");

        linkedHashMap.entrySet().forEach((e) -> {
            System.out.print(e.getKey() + " : " + e.getValue() + ", ");
        });


        System.out.println("\n\nHashMap (1): ");
        hashMap.forEach((k,v) -> { System.out.print(k + " (#:"+k.hashCode() + "):" + v + ", "); });

        System.out.println("\nHashMap (2): ");

        hashMap.entrySet().forEach((e) -> {
            System.out.print(e.getKey() + " : " + e.getValue() + ", ");
        });
    }
}

LinkedHashMap (1):

10 (# = 10): 10, 9 (# = 9): 9, 8 (# = 8): 8, 7 (# = 7): 7, 6 (# = 6): 6, 5 (# = 5 ): 5, 4 (# = 4): 4, 3 (# = 3): 3, 2 (# = 2): 2, 1 (# = 1): 1, 0 (# = 0): 0,

LinkedHashMap (2):

10: 10, 9: 9, 8: 8, 7: 7, 6: 6, 5: 5, 4: 4, 3: 3, 2: 2, 1: 1, 0: 0,

HashMap (1):

0 (#: 0): 0, 1 (#: 1): 1, 2 (#: 2): 2, 3 (#: 3): 3, 4 (#: 4): 4, 5 (#: 5 ): 5, 6 (#: 6): 6, 7 (#: 7): 7, 8 (#: 8): 8, 9 (#: 9): 9, 10 (#: 10): 10,

HashMap (2):

0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, 10: 10,


Più compatto con Java 8:

map.entrySet().forEach(System.out::println);

Prova questo con Java 1.4:

for( Iterator entries = myMap.entrySet().iterator(); entries.hasNext();){

  Entry entry = (Entry) entries.next();

  System.out.println(entry.getKey() + "/" + entry.getValue());

  //...
}

Questa è una domanda in due parti:

Come scorrere le voci di una mappa - @ ScArcher2 ha answered perfettamente.

Qual è l'ordine di iterazione : se stai usando Map , in senso stretto, non ci sono garanzie di ordinazione . Quindi non dovresti fare affidamento sull'ordinazione data da nessuna implementazione. Tuttavia, l'interfaccia SortedMap estende Map e fornisce esattamente ciò che stai cercando: le implementazioni assegneranno un ordinamento coerente.

NavigableMap è un'altra estensione utile : si tratta di una SortedMap con metodi aggiuntivi per trovare le voci in base alla posizione ordinata nel set di chiavi. Quindi, potenzialmente, questo può rimuovere la necessità di iterare in primo luogo: potresti essere in grado di trovare la entry specifica dopo aver utilizzato i higherEntry , lowerEntry , ceilingEntry o floorEntry . Il metodo descendingMap ti fornisce anche un metodo esplicito per invertire l'ordine di attraversamento .


Sì, come molte persone hanno convenuto che questo è il modo migliore per scorrere su una Map .

Ma ci sono possibilità di lanciare nullpointerexception se la mappa è null . Non dimenticare di inserire null .check in.

                                                 |
                                                 |
                                         - - - -
                                       |
                                       |
for (Map.Entry<String, Object> entry : map.entrySet()) {
    String key = entry.getKey();
    Object value = entry.getValue();
}

Se hai una mappa generica non tipizzata puoi usare:

Map map = new HashMap();
for (Map.Entry entry : ((Set<Map.Entry>) map.entrySet())) {
    System.out.println(entry.getKey() + "/" + entry.getValue());
}

Usa Java 8:

map.entrySet().forEach(entry -> System.out.println(entry.getValue()));

           //Functional Oprations
            Map<String, String> mapString = new HashMap<>();
            mapString.entrySet().stream().map((entry) -> {
                String mapKey = entry.getKey();
                return entry;
            }).forEach((entry) -> {
                String mapValue = entry.getValue();
            });

            //Intrator
            Map<String, String> mapString = new HashMap<>();
            for (Iterator<Map.Entry<String, String>> it = mapString.entrySet().iterator(); it.hasNext();) {
                Map.Entry<String, String> entry = it.next();
                String mapKey = entry.getKey();
                String mapValue = entry.getValue();
            }

            //Simple for loop
            Map<String, String> mapString = new HashMap<>();
            for (Map.Entry<String, String> entry : mapString.entrySet()) {
                String mapKey = entry.getKey();
                String mapValue = entry.getValue();

            }

    Iterator iterator = map.entrySet().iterator();
    while (iterator.hasNext()) {
        Map.Entry element = (Map.Entry)it.next();
        LOGGER.debug("Key: " + element.getKey());
        LOGGER.debug("value: " + element.getValue());    
    }

Map<String, String> map = ...
for (Map.Entry<String, String> entry : map.entrySet())
{
    System.out.println(entry.getKey() + "/" + entry.getValue());
}

package com.test;

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

public class Test {

    public static void main(String[] args) {
        Map<String, String> map = new HashMap<String, String>();
        map.put("ram", "ayodhya");
        map.put("krishan", "mathura");
        map.put("shiv", "kailash");

        System.out.println("********* Keys *********");
        Set<String> keys = map.keySet();
        for (String key : keys) {
            System.out.println(key);
        }

        System.out.println("********* Values *********");
        Collection<String> values = map.values();
        for (String value : values) {
            System.out.println(value);
        }

        System.out.println("***** Keys and Values (Using for each loop) *****");
        for (Map.Entry<String, String> entry : map.entrySet()) {
            System.out.println("Key: " + entry.getKey() + "\t Value: "
                    + entry.getValue());
        }

        System.out.println("***** Keys and Values (Using while loop) *****");
        Iterator<Entry<String, String>> entries = map.entrySet().iterator();
        while (entries.hasNext()) {
            Map.Entry<String, String> entry = (Map.Entry<String, String>) entries
                    .next();
            System.out.println("Key: " + entry.getKey() + "\t Value: "
                    + entry.getValue());
        }

        System.out
                .println("** Keys and Values (Using java 8 using lambdas )***");
        map.forEach((k, v) -> System.out
                .println("Key: " + k + "\t value: " + v));
    }
}




iteration