Питання Ітерація через HashMap [дубльований]


Можливі дублікати: 
Як ефективно прослідкувати над кожним входом у "карті"?

Який найкращий спосіб переглянути елементи у a HashMap?


2833
2018-06-30 23:24


походження


Мені потрібно отримати ключі та цінності та додати їх до багатовимірного масиву - burntsugar
Як це має більший бал, ніж питання, що є дублікат? - immibis
У Java 8, використовуючи Lambda Expression: stackoverflow.com/a/25616206/1503859 - Nitin Mahesh
@immibis, ймовірно, тому що багато людей інстинктивно використовують HashMaps без розгляду інших реалізацій карти. Потім, коли вони неминуче застряють, намагаючись переглянути свої HashMap, вони виводять на Google "Iterate through HashMap", що веде їх прямо тут. - Dean Wild


Відповіді:


Ітератуйте через entrySet() подобається так:

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

Докладніше про Map.


2842
2018-06-30 23:27



Незважаючи на старий стиль, це допоможе уникнути ConcurrentModificationExceptions щодо нового стилю foreach у відповідях нижче. Ви можете, наприклад, видалити за допомогою окремого ітератора. - Benjamin Wootton
@ karim79 що ти думаєш про такий спосіб: 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
зателефонувавши "it.remove (); 'ви спорожніли карту, зробивши її неможливою багаторазово, якщо ця карта була змінною класу. У вас є якесь рішення? - vimukthi
@Вімутхі, що ви маєте на увазі вирішення цього? Просто видаліть it.remove(); лінія - Danny
Для (Map.Entry<String, Object> cursor : map.entrySet()) {...} Синтаксис набагато краще. - Chad Okere


Якщо вас цікавлять лише ключі, ви можете прокручувати їх через keySet() на карті:

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

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

Якщо вам потрібні лише значення, скористайтеся values():

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

Нарешті, якщо ви хочете використовувати як ключ, так і значення, скористайтеся entrySet():

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

Одне застереження: якщо ви хочете видалити елементи середньої ітерації, вам потрібно це зробити через ітератор (див відповідь karim79) Однак, зміна значень елемента є OK (див Map.Entry)


4130
2018-06-30 23:28



Так як зробити цикл через 2 карти одночасно? використовуючи метод entrySet? Я спробував використовувати &&, але це робота ddnt - DaMainBoss
Використовуйте два ітератори. Перегляньте прийняту відповідь, наприклад, використання ітератора. - harto
Використання EntrySet є більш ефективним, коли вам потрібні обидві клавіші та значення. Якщо вам потрібен лише той або інший, просто використовуйте таке: stackoverflow.com/questions/3870064/... - rogerdpack
Ще один важливий момент - набір, повернутий keySet () і Колекцією, повернутими значеннями (), обидва підтримуються оригінальною картою. Тобто, якщо ви внесете будь-які зміни в них, вони будуть відображатися назад на Карті, однак обидві вони не підтримують методи add () і addAll (), тобто ви не можете додати нову клавішу до набору чи нове значення в колекції. - sactiw
Про одержання обох значень та ключів, не просто використовувати перший foreach приклад і отримати значення всередині циклу, з value = map.get(key)? Чи є продуктивність entrySet більш високий? - Marco Sulla


Витяг з посилання Як ітерацію над картою в Java:

Існує декілька способів повторення через a Map в Java Давайте розглянемо найбільш поширені методи та розглянемо їх переваги та недоліки. Оскільки всі карти Java реалізують інтерфейс Map, наступні методи будуть працювати для будь-якої реалізації карти (HashMap, TreeMap, LinkedHashMap, Hashtableі т. д.)

Метод №1: Ітератування записів за допомогою циклу For-Each.

Це найпоширеніший спосіб і переважно в більшості випадків. Це слід використовувати, якщо вам потрібні обидва клавіші та значення в циклі.

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

Зверніть увагу, що кожен цикл був введений в Java 5, тому цей метод працює тільки в новіших версіях мови. Також буде викиданий цикл For-Each NullPointerException якщо ви намагаєтесь прокрутити карту, яка є нульовою, то перед повторенням ви завжди повинні перевіряти нульові посилання.

Метод №2: Ітерація над клавішами або значеннями за допомогою циклу For-Each.

Якщо вам потрібні лише ключі або значення на карті, ви можете прокручувати ключові параметри або значення, а не enterSet.

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

Цей метод дає легку перевагу перед продуктивністю entrySet ітерація (приблизно на 10% швидше) і більш чиста.

Метод №3: Ітератування за допомогою ітератора.

Використання 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());
}

Без генериків:

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

Ви також можете використовувати таку саму техніку, щоб ітерації keySet або значення.

Цей метод може виглядати зайвим, але має свої переваги. Перш за все, це єдиний спосіб переглянути карту в старих версіях Java. Іншою важливою особливістю є те, що це єдиний метод, який дозволяє видаляти записи з карти під час ітерації за допомогою виклику iterator.remove(). Якщо ви намагатиметесь зробити це під час "Кожної ітерації", ви отримаєте "непередбачувані результати" згідно з Джавадок.

З точки зору продуктивності цей метод дорівнює тотальній ітерації For-Every.

Метод №4: Ітерація над клавішами та пошук значень (неефективна).

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

Це може виглядати як більш чиста альтернатива для методу №1, але на практиці вона досить повільна та неефективна, оскільки отримання ключових значень може зайняти багато часу (цей метод в різних варіантах Карт становить 20% -200% повільніше, ніж метод № 1 ) Якщо ви встановили FindBugs, він виявить це і попередить вас про неефективну ітерацію. Цей метод слід уникати.

Висновок:

Якщо вам потрібні лише ключі або значення з карти, скористайтеся методом №2. Якщо ви застрягли з більш старою версією Java (менше 5) або плануєте видалити записи під час ітерації, вам слід скористатися методом №3. В іншому випадку використовуйте метод №1.


740
2017-12-08 14:19



Давайте додамо маленьку кришку, що в разі ConcurrentMapс, ітерація на keySet() буде в цілому збоїти (немає гарантії, що існують значення для раніше зібраних ключів). З іншого боку, використання ітераторів чи записів є безпечним (вони завжди стосуються існуючих об'єктів). - P Marecki
@arvind Як би метод № 4 колись був неефективним? За визначенням, викликає get() завжди є O (1) для HashMap. Це визначення HashMap, і користувач запитував HashMap. Я не розумію, чому це так високо оцінено. Якщо ви збираєтеся посилатись на чужого посилання, переконайтеся, що це дійсно має сенс для запитання. - ohbrobig


Ви можете прокручувати записи в a Map в декількох напрямках. Отримати кожну клавішу та оцінити так:

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

Або ви можете отримати список ключів з

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

Якщо ви просто хочете отримати всі значення і не стосуються клавіш, ви можете використовувати:

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





Розумніше:

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

55
2017-08-11 10:01



це насправді залежить від того, чи вам потрібні ключі. якщо ні, то більш ефективно використовувати entrySet (), оскільки hashCode () не викликається. - icfantv
map.get (ключ) для кожної ітерації не розумніше - його спосіб повільніше - ComputerEngineer88
map.entrySet (), який повертає записи, які вже містять як ключ, так і значення. Таким чином, вам не потрібно викликати hashCode () і шукати хеш під час ітерації. - ComputerEngineer88
Синтаксис Java 8. Може все ще не працює для розробки Android. "Android не має наміру бути 100% сумісним з будь-якою версією Java SE API, а не 6, ні 8, ні ніякими ... JRE - це Java Runtime Environment, тоді як JDK - це набір Java Development Kit - JDK, який вам потрібен для розробки додатків для Android разом з існуючим Android SDK.Деці 9, 2013 " джерело - jasonleonhard


Залежить Якщо ви знаєте, що вам знадобиться як ключ, так і значення кожного запису, перейдіть за допомогою entrySet. Якщо вам просто потрібні значення, то є values() метод І якщо вам просто потрібні ключі, то використовуйте keyset().

Погана практика полягає в тому, щоб ітерації за допомогою всіх ключів, а потім і в рамках циклу завжди map.get(key) щоб отримати цінність. Якщо ви це робите, то перший варіант, який я написав, - це для вас.


40
2018-06-30 23:29



Ще один важливий момент - набір, повернутий keySet () і Колекцією, повернутими значеннями (), обидва підтримуються оригінальною картою. Тобто, якщо ви внесете будь-які зміни в них, вони будуть відображатися назад на Карті, однак обидві вони не підтримують методи add () і addAll (), тобто ви не можете додати нову клавішу до набору чи нове значення в колекції. - sactiw