Pytanie Iteracja poprzez HashMap [duplikat]


Możliwe duplikaty: 
Jak skutecznie iterować po każdym wpisie w "Mapie"?

Jaki jest najlepszy sposób na powtórzenie pozycji w pliku HashMap?


2833
2018-06-30 23:24


pochodzenie


Muszę uzyskać klucze i wartości i dodać je do tablicy wielowymiarowej - burntsugar
Jak to ma wyższy wynik niż pytanie, które jest duplikatem? - immibis
W języku Java 8 przy użyciu wyrażenia Lambda: stackoverflow.com/a/25616206/1503859 - Nitin Mahesh
@immibis prawdopodobnie dlatego, że wiele osób instynktownie używa HashMaps bez uwzględnienia innych implementacji map. Potem, gdy nieuchronnie utkną, próbując powtórzyć swój HashMap, uderzają w Google "Iterate through HashMap", prowadząc ich prosto tutaj. - Dean Wild


Odpowiedzi:


Iteruj przez entrySet() jak na przykład:

public static void printMap(Map mp) {
    Iterator it = mp.entrySet().iterator();
    while (it.hasNext()) {
        Map.Entry pair = (Map.Entry)it.next();
        System.out.println(pair.getKey() + " = " + pair.getValue());
        it.remove(); // avoids a ConcurrentModificationException
    }
}

Czytaj więcej na temat Map.


2842
2018-06-30 23:27



Choć stary styl, pomoże to uniknąć ConcurrentModificationExceptions w nowym stylu foreach w poniższych odpowiedziach. Można na przykład usunąć za pomocą oddzielnego iteratora. - Benjamin Wootton
@ karim79 co myślisz o następujący sposób: Map<Integer, Integer> map = new HashMap<Integer, Integer>(); for (Map.Entry<Integer, Integer> entry : map.entrySet()) { System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue()); } - fresh_dev
przez wywołanie "it.remove (); "opróżniasz mapę, dzięki czemu nie można jej użyć ponownie, jeśli ta mapa jest zmienną klasy. Czy masz jakieś rozwiązanie? - vimukthi
@vimukthi, co masz na myśli rozwiązanie tego? Po prostu usuń it.remove(); linia. - Danny
The for (Map.Entry<String, Object> cursor : map.entrySet()) {...} składnia jest znacznie lepsza. - Chad Okere


Jeśli interesują Cię tylko klucze, możesz wykonać iterację po keySet() mapy:

Map<String, Object> map = ...;

for (String key : map.keySet()) {
    // ...
}

Jeśli potrzebujesz tylko wartości, użyj values():

for (Object value : map.values()) {
    // ...
}

Na koniec, jeśli chcesz mieć zarówno klucz, jak i wartość, użyj entrySet():

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

Jedno zastrzeżenie: jeśli chcesz usunąć elementy w połowie iteracji, musisz to zrobić poprzez Iterator (patrz Odpowiedź karim79). Jednak zmiana wartości pozycji jest OK (patrz Map.Entry).


4130
2018-06-30 23:28



A więc jak wykonać pętlę na dwóch mapach jednocześnie? za pomocą metody entrySet? Próbowałem użyć &&, ale to ddnt pracy - DaMainBoss
Użyj dwóch iteratorów. Zobacz akceptowaną odpowiedź, na przykład użycie iteratora. - harto
Używanie entrySet jest bardziej efektywne, gdy potrzebujesz kluczy i wartości. Jeśli potrzebujesz tylko jednego lub drugiego, po prostu użyj tego: stackoverflow.com/questions/3870064/... - rogerdpack
Jeszcze jeden ważny punkt, Zbiór zwracany przez keySet () i Collection zwrócone przez wartości () są poparte oryginalną mapą. Oznacza to, że jeśli wprowadzisz w nich jakąkolwiek modyfikację, zostaną one ponownie odzwierciedlone na mapie, jednak oba nie obsługują metod add () i addAll (), tzn. Nie można dodać nowego klucza do zestawu lub nowej wartości w kolekcji. - sactiw
O uzyskaniu wartości i kluczy nie jest prostsze użycie pierwszego foreach przykład i uzyskaj wartość wewnątrz pętli, przy pomocy value = map.get(key)? Czy wydajność entrySet bardziej wysoki? - Marco Sulla


Wyodrębniono z pliku referencyjnego Jak iterować po mapie w Javie:

Istnieje kilka sposobów na iterowanie po Map w Javie. Przeanalizujmy najbardziej popularne metody i przejrzyj ich zalety i wady. Ponieważ wszystkie mapy w Javie implementują interfejs Map, poniższe techniki będą działać dla każdej implementacji mapy (HashMap, TreeMap, LinkedHashMap, Hashtableitp.)

Metoda nr 1: Iterowanie nad wpisami za pomocą pętli For-Each.

Jest to najczęściej stosowana metoda i jest preferowana w większości przypadków. Należy go użyć, jeśli potrzebujesz zarówno kluczy map, jak i wartości w pętli.

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

Zwróć uwagę, że pętla For-Each została wprowadzona w Javie 5, więc ta metoda działa tylko w nowszych wersjach tego języka. Pętla For-Each również zostanie rzucona NullPointerException jeśli próbujesz iterować na mapie, która jest zerowa, więc przed iteracją zawsze powinieneś sprawdzić referencje zerowe.

Metoda nr 2: Iteracja kluczy lub wartości za pomocą pętli For-Each.

Jeśli potrzebujesz tylko kluczy lub wartości z mapy, możesz dokonać iteracji przez keySet lub wartości zamiast entrySet.

Map<Integer, Integer> map = new HashMap<Integer, Integer>();

// Iterating over keys only
for (Integer key : map.keySet()) {
    System.out.println("Key = " + key);
}

// Iterating over values only
for (Integer value : map.values()) {
    System.out.println("Value = " + value);
}

Ta metoda daje niewielką przewagę wydajności nad entrySet iteracja (około 10% szybsza) i jest bardziej czysta.

Metoda nr 3: Iterowanie za pomocą Iteratora.

Korzystanie z generics:

Map<Integer, Integer> map = new HashMap<Integer, Integer>();
Iterator<Map.Entry<Integer, Integer>> entries = map.entrySet().iterator();
while (entries.hasNext()) {
    Map.Entry<Integer, Integer> entry = entries.next();
    System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
}

Bez generics:

Map map = new HashMap();
Iterator entries = map.entrySet().iterator();
while (entries.hasNext()) {
    Map.Entry entry = (Map.Entry) entries.next();
    Integer key = (Integer)entry.getKey();
    Integer value = (Integer)entry.getValue();
    System.out.println("Key = " + key + ", Value = " + value);
}

Możesz także użyć tej samej techniki do iterowania keySet lub wartości.

Ta metoda może wyglądać na zbędną, ale ma swoje zalety. Przede wszystkim jest to jedyny sposób na powtórzenie mapy w starszych wersjach Javy. Inną ważną cechą jest to, że jest to jedyna metoda, która pozwala na usuwanie wpisów z mapy podczas iteracji przez wywołanie iterator.remove(). Jeśli spróbujesz to zrobić podczas For-Each iteration, otrzymasz "nieprzewidywalne wyniki" według Javadoc.

Z punktu widzenia wydajności ta metoda jest równa dla każdej iteracji.

Metoda nr 4: Iterowanie po klawiszach i wyszukiwanie wartości (nieefektywne).

Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for (Integer key : map.keySet()) {
    Integer value = map.get(key);
    System.out.println("Key = " + key + ", Value = " + value);
}

Może to wyglądać jak czystsza alternatywa dla metody # 1, ale w praktyce jest dość powolna i nieefektywna, ponieważ pobieranie wartości przez klucz może być czasochłonne (ta metoda w różnych implementacjach Map jest o 20% -200% wolniejsza niż metoda # 1 ). Jeśli masz zainstalowane FindBugs, wykryje to i ostrzeże o nieefektywnej iteracji. Tej metody należy unikać.

Wniosek:

Jeśli potrzebujesz tylko kluczy lub wartości z mapy, użyj metody # 2. Jeśli utkniesz przy starszej wersji Java (mniej niż 5) lub planujesz usunąć wpisy podczas iteracji, musisz użyć metody # 3. W przeciwnym razie użyj metody # 1.


740
2017-12-08 14:19



Dodajmy małą cewkę, która w przypadku ConcurrentMaps, iteracja włączona keySet() generalnie ulegnie awarii (nie ma gwarancji, że wartości istnieją dla wcześniej zebranych kluczy). Z drugiej strony używanie iteratorów lub wpisów jest bezpieczne (zawsze odnoszą się do istniejących obiektów). - P Marecki
@arvind Jak metoda nr 4 byłaby nieefektywna? Z definicji dzwonienie get() jest zawsze O (1) dla HashMap. Taka jest definicja HashMap, a użytkownik poprosił o HashMap. Nie rozumiem, dlaczego jest to tak bardzo przegłosowane. Jeśli zamierzasz odwoływać się do linku kogoś innego, upewnij się, że ma to sens w odpowiedzi na zadane pytanie. - ohbrobig


Możesz iterować przez wpisy w a Map na kilka sposobów. Uzyskaj każdy klucz i wartość w następujący sposób:

Map<?,?> map = new HashMap<Object, Object>();
for(Entry<?, ?> e: map.entrySet()){
    System.out.println("Key " + e.getKey());
    System.out.println("Value " + e.getValue());
}

Lub możesz uzyskać listę kluczy za pomocą

Collection<?> keys = map.keySet();
for(Object key: keys){
    System.out.println("Key " + key);
    System.out.println("Value " + map.get(key));
}

Jeśli chcesz uzyskać wszystkie wartości i nie dotyczą kluczy, możesz użyć:

Collection<?> values = map.values();

77
2018-06-30 23:43





for (Map.Entry<String, String> item : params.entrySet()) {
    String key = item.getKey();
    String value = item.getValue();
}

70
2017-07-23 01:28





Mądrzejszy:

for (String key : hashMap.keySet()) {
    System.out.println("Key: " + key + ", Value: " + map.get(key));
}

55
2017-08-11 10:01



to zależy od tego, czy potrzebujesz kluczy, czy nie. jeśli nie, bardziej efektywne jest użycie metody entrySet (), ponieważ metoda hashCode () nie jest wywoływana. - icfantv
map.get (key) dla każdej iteracji nie jest mądrzejszy - jest wolniejszy - ComputerEngineer88
map.entrySet (), która zwraca wpisy, które już zawierają zarówno klucz, jak i wartość. W ten sposób nie musisz wywoływać hashCode () i przeszukiwać hasha podczas iteracji. - ComputerEngineer88
Składnia Java 8. Nadal może nie działać na Androida. "Android nie jest w 100% kompatybilny z żadną wersją Java SE API, a nie 6 ani 8, ani żadną. ... JRE to Java Runtime Environment, a JDK to Java Development Kit. do tworzenia aplikacji na Androida wraz z istniejącym pakietem SDK do Androida SD 9, 2013 " źródło - jasonleonhard


Zależy. Jeśli wiesz, że będziesz potrzebować zarówno klucza, jak i wartości każdego wpisu, przejdź do entrySet. Jeśli potrzebujesz tylko wartości, to jest values() metoda. A jeśli potrzebujesz tylko kluczy, użyj keyset().

Złą praktyką byłoby powtarzanie wszystkich kluczy, a następnie w pętli, zawsze robić map.get(key) aby uzyskać wartość. Jeśli to robisz, to pierwsza opcja, którą napisałem, jest dla ciebie.


40
2018-06-30 23:29



Jeszcze jeden ważny punkt, Zbiór zwracany przez keySet () i Collection zwrócone przez wartości () są poparte oryginalną mapą. Oznacza to, że jeśli wprowadzisz w nich jakąkolwiek modyfikację, zostaną one ponownie odzwierciedlone na mapie, jednak oba nie obsługują metod add () i addAll (), tzn. Nie można dodać nowego klucza do zestawu lub nowej wartości w kolekcji. - sactiw