java - 方法 - map entryset loop
Javaマップの各エントリを効率的に反復処理する方法 (20)
ラムダ式Java 8
Java 1.8(Java 8)では、 Iterable Interfaceのイテレータに似たAggregate操作( ストリーム操作 )のforEachメソッドを使用すると、これはもっと簡単になりました。
下のステートメントをコードにコピーして、 HashMap変数をhmから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 Docsへのドキュメント・リンクを含みます。 ラムダの詳細については、このlinkしてlink 。 集計オペレーションを読んで、Spliteratorにはこのlinkしてlink 。
JavaでMap
インターフェイスを実装するオブジェクトを持っていて、その中に含まれるすべてのペアを繰り返し処理したい場合は、マップを通過する最も効率的な方法は何ですか?
要素の順序付けは、私がインタフェース用に持っている特定のマップ実装に依存しますか?
Java 1.4でこれを試してみてください:
for( Iterator entries = myMap.entrySet().iterator(); entries.hasNext();){
Entry entry = (Entry) entries.next();
System.out.println(entry.getKey() + "/" + entry.getValue());
//...
}
Java 8では、新しいlambdaの機能を使用して、クリーンで高速に処理できます。
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
の型はコンパイラによって推論され、 Map.Entry
を使用する必要はもうありません。
イージーピーシー!
Java 8で最もコンパクト:
map.entrySet().forEach(System.out::println);
Eclipse Collections (以前のGS Collections )では、 MapIterableインターフェースでforEachKeyValueメソッドを使用します。これは、 MapIterableインターフェースと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 Collectionsのコミッターです。
map.keySet()
とmap.values()
使用することもできます。マップのキー/値のみに興味がある場合はmap.keySet()
を使用します。
Java 8:
ラムダ式を使うことができます:
myMap.entrySet().stream().forEach((entry) -> {
Object currentKey = entry.getKey();
Object currentValue = entry.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());
}
これを行う方法はたくさんあります。 以下は簡単な手順です:
次のような1つのマップがあるとします。
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));
}
これを行う正しい方法は、受け入れられた答えを最も効率的なものとして使用することです。 私は次のコードが少しきれいに見えます。
for (String key: map.keySet()) {
System.out.println(key + "/" + map.get(key));
}
はい、順序は特定のマップ実装によって異なります。
@ 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();
// ...
}
イテレータとジェネリックスの使用例:
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();
// ...
}
マップを反復する典型的なコードは次のとおりです。
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
は自然な順序でキーのエントリを返します。
(更新:これはもはや真実ではないと思います ) entrySet
イテレータは、現在、 entrySet
内のすべてのアイテムに対して同じMap.Entry
インスタンスを返す固有の実装を持っています。 しかし、イテレータが新しくなるたびにMap.Entry
が更新されます。
マップを反復処理する方法はいくつかあります。
マップに格納されている共通のデータセットに対するパフォーマンスを比較し、100万のキー値のペアをマップに格納し、マップ全体を反復処理します。
1)各ループにentrySet()
)を使用する
for (Map.Entry<String,Integer> entry : testMap.entrySet()) {
entry.getKey();
entry.getValue();
}
50ミリ秒
2)各ループにkeySet()
)を使用する
for (String key : testMap.keySet()) {
testMap.get(key);
}
76ミリ秒
3) entrySet()
とイテレータを使用する
Iterator<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()
とイテレータを使用する
Iterator itr2 = testMap.keySet().iterator();
while(itr2.hasNext()) {
String key = itr2.next();
testMap.get(key);
}
75ミリ秒
私はthis link
。
他の答えを要約し、私が知っているものと組み合わせるために、私はこれを行う10の主な方法を見つけました(下記参照)。 また、私はいくつかのパフォーマンステストを書いた(下記の結果を参照)。 たとえば、マップのすべてのキーと値の合計を求める場合は、次のように書くことができます。
イテレータとMap.Entryの使用
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とMap.Entryの使用
long i = 0; for (Map.Entry<Integer, Integer> pair : map.entrySet()) { i += pair.getKey() + pair.getValue(); }
Java 8からのforEachの使用
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); }
forとMap.Entryの使用
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の並列使用
final long[] i = {0}; map.entrySet().stream().parallel().forEach(e -> i[0] += e.getKey() + e.getValue());
Apache Collections
IterableMapの使用long i = 0; MapIterator<Integer, Integer> it = iterableMap.mapIterator(); while (it.hasNext()) { i += it.next() + it.getValue(); }
Eclipse(CS)コレクションのMutableMapの使用
final long[] i = {0}; mutableMap.forEachKeyValue((key, value) -> { i[0] += key + value; });
パフォーマンステスト (モード= AverageTime、システム= Windows 8.1 64ビット、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 。
理論的には、最も効率的な方法はマップの実装に依存します。 これを行う公式の方法は、それぞれがキーと値( entry.getKey()
とentry.getValue()
)を含むMap.Entry
セットを返すmap.entrySet()
を呼び出すことmap.entrySet()
。
特異な実装では、 map.keySet()
、 map.entrySet()
などを使用するかどうかに違いがあります。 しかし、誰もがそれを書くような理由は考えられません。 ほとんどの場合、あなたが行っていることとパフォーマンスに大きな違いはありません。
そして、はい、順序は、インプリメンテーションと、挿入の順序や制御が難しい要素(おそらく)に依存します。
[edit]元々 valueSet()
を書きvalueSet()
が、もちろんentrySet()
は実際には答えです。
//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));
}
}