Как эффективно перебирать каждую запись в карте Java?
Если у меня есть объект, реализующий Map интерфейс в Java, и я хочу перебирать каждую пару, содержащуюся в нем, каков наиболее эффективный способ прохождения карты?
будет ли порядок элементов зависеть от конкретной реализации карты, которую я имею для интерфейса?
30 ответов:
Map<String, String> map = ... for (Map.Entry<String, String> entry : map.entrySet()) { System.out.println(entry.getKey() + "/" + entry.getValue()); }
используя итератор и карта.Запись
long i = 0; Iterator<Map.Entry<Integer, Integer>> it = map.entrySet().iterator(); while (it.hasNext()) { Map.Entry<Integer, Integer> pair = it.next(); i += pair.getKey() + pair.getValue(); }используя foreach и карта.Запись
long i = 0; for (Map.Entry<Integer, Integer> pair : map.entrySet()) { i += pair.getKey() + pair.getValue(); }используя forEach из Java 8
final long[] i = {0}; map.forEach((k, v) -> i[0] += k + v);используя keySet и foreach
long i = 0; for (Integer key : map.keySet()) { i += key + map.get(key); }используя keySet и итератор
long i = 0; Iterator<Integer> itr2 = map.keySet().iterator(); while (itr2.hasNext()) { Integer key = itr2.next(); i += key + map.get(key); }используя на и карта.Запись
long i = 0; for (Iterator<Map.Entry<Integer, Integer>> entries = map.entrySet().iterator(); entries.hasNext(); ) { Map.Entry<Integer, Integer> entry = entries.next(); i += entry.getKey() + entry.getValue(); }использование Java 8 Stream API
final long[] i = {0}; map.entrySet().stream().forEach(e -> i[0] += e.getKey() + e.getValue());использование Java 8 Stream API parallel
final long[] i = {0}; map.entrySet().stream().parallel().forEach(e -> i[0] += e.getKey() + e.getValue());используя IterableMap на
Apache Collectionslong i = 0; MapIterator<Integer, Integer> it = iterableMap.mapIterator(); while (it.hasNext()) { i += it.next() + it.getValue(); }используя MutableMap "затмение" (стр.) коллекции
final long[] i = {0}; mutableMap.forEachKeyValue((key, value) -> { i[0] += key + value; });тесты производительности (mode = AverageTime, system = Windows 8.1 64-bit, Intel i7-4790 3.60 GHz, 16 GB)
для небольшой карты (100 элементов), оценка 0,308 является лучшим
Benchmark Mode Cnt Score Error Units test3_UsingForEachAndJava8 avgt 10 0.308 ± 0.021 µs/op test10_UsingEclipseMap avgt 10 0.309 ± 0.009 µs/op test1_UsingWhileAndMapEntry avgt 10 0.380 ± 0.014 µs/op test6_UsingForAndIterator avgt 10 0.387 ± 0.016 µs/op test2_UsingForEachAndMapEntry avgt 10 0.391 ± 0.023 µs/op test7_UsingJava8StreamApi avgt 10 0.510 ± 0.014 µs/op test9_UsingApacheIterableMap avgt 10 0.524 ± 0.008 µs/op test4_UsingKeySetAndForEach avgt 10 0.816 ± 0.026 µs/op test5_UsingKeySetAndIterator avgt 10 0.863 ± 0.025 µs/op test8_UsingJava8StreamApiParallel avgt 10 5.552 ± 0.185 µs/opдля карты с 10000 элементов, оценка 37.606 является лучшим
Benchmark Mode Cnt Score Error Units test10_UsingEclipseMap avgt 10 37.606 ± 0.790 µs/op test3_UsingForEachAndJava8 avgt 10 50.368 ± 0.887 µs/op test6_UsingForAndIterator avgt 10 50.332 ± 0.507 µs/op test2_UsingForEachAndMapEntry avgt 10 51.406 ± 1.032 µs/op test1_UsingWhileAndMapEntry avgt 10 52.538 ± 2.431 µs/op test7_UsingJava8StreamApi avgt 10 54.464 ± 0.712 µs/op test4_UsingKeySetAndForEach avgt 10 79.016 ± 25.345 µs/op test5_UsingKeySetAndIterator avgt 10 91.105 ± 10.220 µs/op test8_UsingJava8StreamApiParallel avgt 10 112.511 ± 0.365 µs/op test9_UsingApacheIterableMap avgt 10 125.714 ± 1.935 µs/opдля карты с 100000 элементов, оценка 1184.767 является лучший
Benchmark Mode Cnt Score Error Units test1_UsingWhileAndMapEntry avgt 10 1184.767 ± 332.968 µs/op test10_UsingEclipseMap avgt 10 1191.735 ± 304.273 µs/op test2_UsingForEachAndMapEntry avgt 10 1205.815 ± 366.043 µs/op test6_UsingForAndIterator avgt 10 1206.873 ± 367.272 µs/op test8_UsingJava8StreamApiParallel avgt 10 1485.895 ± 233.143 µs/op test5_UsingKeySetAndIterator avgt 10 1540.281 ± 357.497 µs/op test4_UsingKeySetAndForEach avgt 10 1593.342 ± 294.417 µs/op test3_UsingForEachAndJava8 avgt 10 1666.296 ± 126.443 µs/op test7_UsingJava8StreamApi avgt 10 1706.676 ± 436.867 µs/op test9_UsingApacheIterableMap avgt 10 3289.866 ± 1445.564 µs/opграфики (тесты производительности в зависимости от размера карты)
таблица (тесты производительности в зависимости от размера карты)
100 600 1100 1600 2100 test10 0.333 1.631 2.752 5.937 8.024 test3 0.309 1.971 4.147 8.147 10.473 test6 0.372 2.190 4.470 8.322 10.531 test1 0.405 2.237 4.616 8.645 10.707 test2 0.376 2.267 4.809 8.403 10.910 test7 0.473 2.448 5.668 9.790 12.125 test9 0.565 2.830 5.952 13.220 16.965 test4 0.808 5.012 8.813 13.939 17.407 test5 0.810 5.104 8.533 14.064 17.422 test8 5.173 12.499 17.351 24.671 30.403все тесты на GitHub.
в Java 8, вы можете сделать это чисто и быстро, используя новые функции лямбды:
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));тип
kиvбудет выведен компилятором и не нужно использовать
да, порядок зависит от конкретной реализации Карты.
@ScArcher2 имеет более элегантный синтаксис Java 1.5. В 1.4, я бы сделал что-то вроде этого:
Iterator entries = myMap.entrySet().iterator(); while (entries.hasNext()) { Entry thisEntry = (Entry) entries.next(); Object key = thisEntry.getKey(); Object value = thisEntry.getValue(); // ... }
типичный код для итерации по карте:
Map<String,Thing> map = ...; for (Map.Entry<String,Thing> entry : map.entrySet()) { String key = entry.getKey(); Thing thing = entry.getValue(); ... }
HashMapявляется канонической реализацией карты и не дает гарантий (или хотя он не должен изменять порядок, если на нем не выполняется операция мутации).SortedMapвернет записи, основанные на естественном порядке ключей, илиComparator, если это предусмотрено.LinkedHashMapбудет либо возвращать записи в порядке вставки или порядке доступа в зависимости от того, как он был построен.EnumMapвозвращает записи в естественном порядке из ключей.(обновление: я думаю, что это не правда.) обратите внимание,
IdentityHashMapentrySetитератор в настоящее время имеет своеобразную реализацию, которая возвращает то же самоеMap.Entryэкземпляр для каждого элемента вentrySet! Однако каждый раз, когда новый итератор продвигаетMap.Entryобновляется.
пример использования итератора и генерики:
Iterator<Map.Entry<String, String>> entries = myMap.entrySet().iterator(); while (entries.hasNext()) { Map.Entry<String, String> entry = entries.next(); String key = entry.getKey(); String value = entry.getValue(); // ... }
это вопрос из двух частей:
как перебирать записи карты - @ScArcher2 имеет ответил это прекрасно.
Каков порядок итерации - если вы просто используя
Map, то, строго говоря, есть нет гарантии заказа. Поэтому вы не должны действительно полагаться на порядок, заданный какой-либо реализацией. Тем не менее,SortedMapинтерфейс расширяетMapи предоставляет именно то, что вы ищете - реализации всегда будут давать последовательный порядок сортировки.
NavigableMapеще одно полезное расширение - этоSortedMapС дополнительными методами поиска записей по их упорядоченному положению в наборе ключей. Таким образом, потенциально это может устранить необходимость итерации в первую очередь - вы можете найти конкретныйentryвы после использованияhigherEntry,lowerEntry,ceilingEntryилиfloorEntryметоды. ЭлементdescendingMapметод даже дает вам явный метод изменение порядка обхода.
есть несколько способов итерации по карте.
вот сравнение их производительности для общего набора данных, хранящегося на карте, сохраняя миллион пар ключевых значений в карте и будет повторяться по карте.
1) с помощью
entrySet()in для каждого циклаfor (Map.Entry<String,Integer> entry : testMap.entrySet()) { entry.getKey(); entry.getValue(); }50 мсек
2) с помощью
keySet()in для каждого циклаfor (String key : testMap.keySet()) { testMap.get(key); }76 миллисекунды
3) с помощью
entrySet()и iteratorIterator<Map.Entry<String,Integer>> itr1 = testMap.entrySet().iterator(); while(itr1.hasNext()) { Map.Entry<String,Integer> entry = itr1.next(); entry.getKey(); entry.getValue(); }50 мсек
4) с помощью
keySet()и iteratorIterator itr2 = testMap.keySet().iterator(); while(itr2.hasNext()) { String key = itr2.next(); testMap.get(key); }75 мс
Я говорил
this link.
к вашему сведению, вы также можете использовать
map.keySet()иmap.values()если вас интересуют только ключи / Значения карты, а не другие.
правильный способ сделать это-использовать принятый ответ, поскольку он является наиболее эффективным. Я нашел следующий код выглядит немного чище.
for (String key: map.keySet()) { System.out.println(key + "/" + map.get(key)); }
С Коллекции Eclipse (ранее коллекции GS), вы бы использовали метод forEachKeyValue на MapIterable интерфейс, который наследуется интерфейсами MutableMap и ImmutableMap и их реализациями.
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);с синтаксисом лямбда Java 8, вы можете написать код следующим образом:
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);Примечание: я коммиттер для коллекций Eclipse.
попробуйте это с Java 1.4:
for( Iterator entries = myMap.entrySet().iterator(); entries.hasNext();){ Entry entry = (Entry) entries.next(); System.out.println(entry.getKey() + "/" + entry.getValue()); //... }
в теории, наиболее эффективный способ будет зависеть от того, какая реализация карты. Официальный способ сделать это-позвонить
map.entrySet(), который возвращает наборMap.Entry, каждый из которых содержит ключ и значение (entry.getKey()иentry.getValue()).в идиосинкразической реализации, это может иметь некоторое значение, используете ли вы
map.keySet(),map.entrySet()или что-то еще. Но я не могу придумать причину, по которой кто-то мог бы написать это так. Скорее всего, это не имеет никакого значения для производительности, что вы делать.и да, порядок будет зависеть от реализации, а также (возможно) порядок вставки и других трудно поддающихся контролю факторов.
[edit] я написал
valueSet()изначально, но конечноentrySet()на самом деле ответ.
Java 8:
вы можете использовать лямбда-выражения:
myMap.entrySet().stream().forEach((entry) -> { Object currentKey = entry.getKey(); Object currentValue = entry.getValue(); });для получения дополнительной информации, следуйте этой.
лямда - Выражение Java 8
в Java 1.8 (Джава 8) это стало намного проще с помощью forEach метод из агрегатных операций (поток операций) это похоже на итераторы из Iterable интерфейс.
просто скопируйте вставить ниже заявление в свой код и переименовать HashMap переменной от хм для вашей переменной HashMap, чтобы распечатать ключ-значение пара.
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.Ниже приведен пример кода, который я попытался с помощью Лямбда-Выражение. Эта штука такая классная. Должны попытаться.
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также можно использовать Spliterator то же самое.
Spliterator sit = hm.entrySet().spliterator();обновление
включая ссылки на документацию к документам Oracle. Для получения дополнительной информации лямда - на этот ссылке и должны читать Совокупность Операций и последний идти к этому ссылке.
в карте можно перебирать
keysи/илиvaluesи/илиboth (e.g., entrySet)зависит от того, кто заинтересован в _ как:1.) Повторите через
keys -> keySet()карты:Map<String, Object> map = ...; for (String key : map.keySet()) { //your Business logic... }2.) Повторите через
values -> values()карты:for (Object value : map.values()) { //your Business logic... }3.) Повторите через
both -> entrySet()карты:for (Map.Entry<String, Object> entry : map.entrySet()) { String key = entry.getKey(); Object value = entry.getValue(); //your Business logic... }кроме того, есть 3 разных способа итерации через хэш-карту. Они как показано ниже_
//1. for (Map.Entry entry : hm.entrySet()) { System.out.print("key,val: "); System.out.println(entry.getKey() + "," + entry.getValue()); } //2. Iterator iter = hm.keySet().iterator(); while(iter.hasNext()) { Integer key = (Integer)iter.next(); String val = (String)hm.get(key); System.out.println("key,val: " + key + "," + val); } //3. Iterator it = hm.entrySet().iterator(); while (it.hasNext()) { Map.Entry entry = (Map.Entry) it.next(); Integer key = (Integer)entry.getKey(); String val = (String)entry.getValue(); System.out.println("key,val: " + key + "," + val); }
public class abcd{ public static void main(String[] args) { Map<Integer, String> testMap = new HashMap<Integer, String>(); testMap.put(10, "a"); testMap.put(20, "b"); testMap.put(30, "c"); testMap.put(40, "d"); for (Integer key:testMap.keySet()) { String value=testMap.get(key); System.out.println(value); } } }или
public class abcd { public static void main(String[] args) { Map<Integer, String> testMap = new HashMap<Integer, String>(); testMap.put(10, "a"); testMap.put(20, "b"); testMap.put(30, "c"); testMap.put(40, "d"); for (Entry<Integer, String> entry : testMap.entrySet()) { Integer key=entry.getKey(); String value=entry.getValue(); } } }
если у вас есть общая нетипизированная Карта, Вы можете использовать:
Map map = new HashMap(); for (Map.Entry entry : ((Set<Map.Entry>) map.entrySet())) { System.out.println(entry.getKey() + "/" + 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<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()); }
Iterator itr2 = testMap.keySet().iterator(); while (itr2.hasNext()) { String key = itr2.next(); testMap.get(key); } for (String key: map.keySet()) { System.out.println(key + "/" + map.get(key)); }лучший способ-это
entrySet()хотя.
в Java 8, у нас есть
forEachметод, который принимает лямбда-выражение. У нас тоже есть поток API-интерфейсы. Рассмотрим карту:Map<String,String> sample = new HashMap<>(); sample.put("A","Apple"); sample.put("B", "Ball");перебирать ключи:
sample.keySet().forEach((k) -> System.out.println(k));перебора значений:
sample.values().forEach((v) -> System.out.println(v));перебирать записи (используя forEach и потоки):
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); });преимущество с потоками является то, что они могут быть распараллелены легко в случае, если мы хотим. Нам просто нужно использовать
parallelStream()на местеstream()выше.
//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(); }
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)); } }
да, как многие люди согласились, что это лучший способ перебирать
Map.но есть шансы бросить
nullpointerexceptionесли картаnull. Не забудьте поставитьnull.регистрация.| | - - - - | | for (Map.Entry<String, Object> entry : map.entrySet()) { String key = entry.getKey(); Object value = entry.getValue(); }
есть много способов сделать это. Ниже приведено несколько простых шагов:
Предположим, у вас есть одна карта, как:
Map<String, Integer> m = new HashMap<String, Integer>();затем вы можете сделать что-то вроде ниже, чтобы перебрать элементы карты.
// ********** 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)); }
порядок всегда будет зависеть от конкретной реализации Карты. С помощью Java 8 вы можете использовать любой из них:
map.forEach((k,v) -> { System.out.println(k + ":" + v); });или:
map.entrySet().forEach((e) -> { System.out.println(e.getKey() + " : " + e.getValue()); });результат будет тот же (тот же порядок). EntrySet поддерживается картой, поэтому вы получаете тот же порядок. Второй удобен, так как позволяет использовать лямбды, например, если вы хотите печатать только целочисленные объекты, которые больше 5:
map.entrySet() .stream() .filter(e-> e.getValue() > 5) .forEach(System.out::println);код ниже показывает итерацию через LinkedHashMap и обычный HashMap (пример). Вы увидите разницу в порядке:
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,

Comments