Javaマップの各エントリを効率的に反復するにはどうすればよいですか?


3302

MapJavaでインターフェースを実装するオブジェクトがあり、その中に含まれるすべてのペアを反復処理したい場合、マップを通過する最も効率的な方法は何ですか?

要素の順序は、インターフェイスにある特定のマップ実装に依存しますか?


38
Lambda式を使用するJava 8の場合:stackoverflow.com/a/25616206/1503859
Nitin Mahesh

回答:


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

93
これを行うと、エントリはマップ内のネストされたクラスであるため、機能しません。java.sun.com/javase/6/docs/api/java/util/Map.html
ScArcher2

266
インポートは「import java.util.Map.Entry;」として記述できます。そしてそれは動作します。
jjujuma

55
@Pureferretイテレータを使用する唯一の理由は、そのremoveメソッドを呼び出す必要がある場合です。その場合は、この別の回答でその方法を示します。それ以外の場合は、上記の回答に示されている拡張ループが適切です。
assylias 2012年

102
Map.Entryフォームは、内部クラスを現在の名前空間にインポートするよりも明確だと思います。
ジョサイアヨーダー14

31
map.values()またはmap.keySet()値またはキーのみをループする場合に使用できます。
dguay 2016年

1216

他の回答を要約し、それらを私が知っていることと組み合わせるために、これを行う10の主な方法を見つけました(以下を参照)。また、いくつかのパフォーマンステストを作成しました(以下の結果を参照)。たとえば、マップのすべてのキーと値の合計を求めたい場合は、次のように書くことができます。

  1. イテレータ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();
    }
  2. foreachMap.Entryの使用

    long i = 0;
    for (Map.Entry<Integer, Integer> pair : map.entrySet()) {
        i += pair.getKey() + pair.getValue();
    }
  3. Java 8からのforEachの使用

    final long[] i = {0};
    map.forEach((k, v) -> i[0] += k + v);
  4. keySetforeachの使用

    long i = 0;
    for (Integer key : map.keySet()) {
        i += key + map.get(key);
    }
  5. keySetイテレーターの使用

    long i = 0;
    Iterator<Integer> itr2 = map.keySet().iterator();
    while (itr2.hasNext()) {
        Integer key = itr2.next();
        i += key + map.get(key);
    }
  6. 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();
    }
  7. Java 8 Stream APIの使用

    final long[] i = {0};
    map.entrySet().stream().forEach(e -> i[0] += e.getKey() + e.getValue());
  8. Java 8 Stream APIの並列使用

    final long[] i = {0};
    map.entrySet().stream().parallel().forEach(e -> i[0] += e.getKey() + e.getValue());
  9. IterableMapの使用Apache Collections

    long i = 0;
    MapIterator<Integer, Integer> it = iterableMap.mapIterator();
    while (it.hasNext()) {
        i += it.next() + it.getValue();
    }
  10. 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)

  1. 小さなマップ(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
  2. 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
  3. 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で行われます


9
@Viacheslav:とてもいい答え。ベンチマークでラムダをキャプチャすることにより、Java8 APIがどのように妨げられるのかと思っているだけです(たとえばlong sum = 0; map.forEach( /* accumulate in variable sum*/);sum長いものをキャプチャしstream.mapToInt(/*whatever*/).sumます。たとえば、言うよりも遅いかもしれません。もちろん、状態のキャプチャを常に回避できるわけではありませんが、それは合理的な追加になる可能性があります。ベンチに
GPI

17
あなたの8テストは間違っています。同期せずに異なるスレッドから同じ変数にアクセスします。に変更しAtomicIntegerて問題を解決してください。
talex

44
@ZhekaKozlov:驚くほど大きなエラー値を見てください。のテスト結果はx±ex-eto からまでの間隔内に結果があったことを意味するx+eため、最も速い結果(1184.767±332.968)は852toの範囲です1518が、2番目に遅い(1706.676±436.867)はとの間1270で実行される2144ため、結果は依然として大幅に重なります。次に、最も遅い結果を見てください3289.866±1445.564。これは18444735との間で分岐することを意味し、これらのテスト結果は無意味であることがわかります。
ホルガー

8
HashMap、LinkedHashMap、TreeMapの3つの主要な実装を比較するとどうでしょうか?
ティエリー

9
#1と#6はまったく同じです。使い方whileforループは、反復ごとに異なる技術ではありません。そして、テストでそれらの間にそのようなばらつきがあることに驚いています。これは、テストが、テストしようとしているものとは無関係の外部要因から適切に分離されていないことを示唆しています。
ErikE

294

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コンパイラーによって推測され、使用する必要はありません。Map.Entryこれ以上ません。

かんたん!


12
マップで何をしたいかに応じて、map.entrySet().stream() docs.oracle.com
javase / 8 / docs / api / java / util / stream / Stream.html

1
forEach()内からラムダ式の外部で宣言されたfinal以外の変数を参照する場合、これは機能しません...
Chris

7
@クリス正解。ラムダの外側からfinal以外の変数を効果的に使用しようとしても機能しません。
コーディネーター

243

はい、順序は特定のマップ実装に依存します。

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

41
whileよりループを優先します。 。
jai

8
@jpredham for構成をそのまま使用してfor (Entry e : myMap.entrySet)もコレクションを変更できないことは正しいですが、@ HanuAthenaが言及した例Iteratorではスコープ内にあるため、機能するはずです。(何か不足している場合を
除き

1
IntelliJでエラーが発生しましたEntry thisEntry = (Entry) entries.next();:が認識されませんEntry。その疑似コードは何か他のものですか?
JohnK、2015年

1
@JohnKインポートしてみてくださいjava.util.Map.Entry
2015年

1
整数キーと文字列キーがある場合、このソリューションは機能しません。

140

マップを反復するための一般的なコードは次のとおりです。

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

HashMap正規マップの実装であり、保証はありません(または、変更操作が実行されない場合、順序は変更されません)。SortedMapは、キーの自然な順序に基づいてエントリを返しますComparatorLinkedHashMap構成方法に応じて、エントリを挿入順またはアクセス順で返します。EnumMapキーの自然な順序でエントリを返します。

(更新:これはもう真実ではないと思います。)注:IdentityHashMap entrySetイテレータには現在Map.EntryentrySet!内のすべてのアイテムに対して同じインスタンスを返す固有の実装があります ただし、新しいイテレータが進むたびにMap.Entry更新されます。


6
EnumMapも、IdentityHashMapと一緒にこの独特の動作をします
Premraj

1
「LinkedHashMapは[...]アクセス順序[...]のエントリを返す」...要素にアクセスする順序で要素にアクセスしますか?トートロジー、または余談を使用できる興味深いもの。;-)
jpaugh 2016年

5
@jpaugh LinkedHashMapカウントへの直接アクセスのみ。これらを通じてはiteratorspliteratorentrySet、など、順序を変更しないでください。
トムホーティン-タックライン2016年

1
1. しかしもし?2.最後の段落は、ブラッシュアップの恩恵を受ける可能性があります。
Peter Mortensen

122

イテレータとジェネリックスの使用例:

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

14
Iteratorスコープを制限するためにforループを配置する必要があります。
Steve Kuo

@SteveKuo「範囲を制限する」とはどういう意味ですか?
StudioWorks、2015

12
@StudioWorks for (Iterator<Map.Entry<K, V>> entries = myMap.entrySet().iterator(); entries.hasNext(); ) { Map.Entry<K, V> entry = entries.next(); }。その構造を使用することにより、(変数の可視性)のスコープをentriesforループに制限します。
ComFreek

3
@ComFreekああ、なるほど。それがそれほど重要であることを知りませんでした。
StudioWorks 2015年

102

これは2つの部分からなる質問です。

マップのエントリを反復処理する方法 -@ ScArcher2は完全にそれに答えました。

反復の順序は何ですか?単に使用しているMap場合、厳密に言うと、順序の保証はありません。そのため、実装によって与えられた順序に実際に依存すべきではありません。ただし、SortedMapインターフェースは拡張してMap、まさにあなたが探しているものを提供します-実装は、一貫したソート順を提供します。

NavigableMapもう1つの便利な拡張機能です。これはSortedMap、キーセット内の順序付けされた位置でエントリを検索するための追加のメソッドです。だから、潜在的にこれは最初の場所で繰り返し処理の必要性を取り除くことができます-あなたは、特定のを見つけることができるかもしれないentryあなたが使用した後ですhigherEntrylowerEntryceilingEntry、またはfloorEntry方法を。このdescendingMap方法では、走査順序逆にする明示的な方法も提供されます。


84

マップを反復する方法はいくつかあります。

これは、100万のキーと値のペアをマップに格納することでマップに格納された一般的なデータセットのパフォーマンスの比較であり、マップを反復処理します。

1)entrySet()for eachループを使用する

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

50ミリ秒

2)keySet()for eachループを使用する

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


1
ランタイムは、Java Microbenchmarking Harnessを使用しない記事から引用しています。たとえば、コードがJITコンパイラによって完全に最適化されている可能性があるため、時間は信頼できません。
AlexB

59

これを行う正しい方法は、最も効率的であるため、受け入れられた回答を使用することです。次のコードは少しきれいに見えます。

for (String key: map.keySet()) {
   System.out.println(key + "/" + map.get(key));
}

15
これは最善の方法ではありません。entrySet()を使用する方がはるかに効率的です。Findbugsはこのコードにフラグを付けます(findbugs.sourceforge.net/…を参照)
Jeff Olson

6
@JeffOlsonまあ、そうではない。マップ検索はO(1)なので、両方のループは同じように動作します。確かに、マイクロベンチマークでは少し遅くなりますが、型引数を何度も書くのが嫌なので、私も時々これを行います。また、これがパフォーマンスのボトルネックになることはほとんどないので、コードが読みやすくなるようにしてください。
kritzikratzi

4
さらに詳しく:O(1) = 2*O(1)ほぼビッグO表記の定義です。あなたはそれが少し遅いという点で正しいですが、複雑さの点ではそれらは同じです。
kritzikratzi

2
衝突かどうかに関係なく、いくつかの衝突があっても問題ではないことを意味します。衝突のみがある場合は、明らかに別の話になります。だからあなたはかなりささいなことですが、うん、あなたの言っていることは本当です。
kritzikratzi

2
@Jeff Olson:「Big O」の複雑さは変わらない、一定の因子しかない場合のコメントは正しいです。それでも、私にとっては、1時間または2時間かかるかどうかが重要です。さらに重要なの 2、を反復してentrySet()もまったくルックアップが行われないため、係数がでないことを強調する必要があります。これは、すべてのエントリを直線的にたどるだけです。これとは対照的に、反復処理keySet()し、キークマあたりのルックアップを実行する1件の我々はゼロ対のルックアップの話をしているので、キーごとに検索をn個、ここで検索、n個のサイズですMap。そのため、要因ははるかに超えてい2ます…
Holger

57

FYI、あなたも使用することができますmap.keySet()し、map.values()あなたが唯一の他のマップのキー/値に興味はないしている場合。


42

Javaの8、あなたは地図のforEachとラムダ式を使用して繰り返すことができ、

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

41

Eclipseのコレクション、あなたが使用するforEachKeyValue上での方法をMapIterableによって継承されるインターフェース、MutableMapおよびImmutableMapインタフェースとその実装。

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

匿名の内部クラスを使用すると、次のようにコードを記述できます。

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

注:私はEclipseコレクションのコミッターです。


37

ラムダ式Java 8

Java 1.8(Java 8)では、Iterableのイテレータに似たAggregateオペレーション(Streamオペレーション)のforEachメソッドを使用することで、これがずっと簡単になりました。 Interfaceの。

以下のステートメントをコピーしてコードにコピーし、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

また、Splitatoratorを使用することもできます。

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

更新


Oracle Docsへのドキュメントへのリンクを含みます。Lambdaの詳細については、このリンクにアクセスし集約操作を読む必要があります。Splitatorについては、このリンクにアクセスしてください


36

理論的には、最も効率的な方法は、Mapの実装によって異なります。これを行う正式な方法は、を呼び出すことです。これは、それぞれにキーと値(および)が含まれるのmap.entrySet()セットを返します。Map.Entryentry.getKey()entry.getValue()

特異な実装では、を使用するかどうかによって多少の違いが生じる可能性がありますmap.keySet()map.entrySet()ます。しかし、誰もがそのように書く理由は考えられません。ほとんどの場合、パフォーマンスに影響はありません。

そして、はい、順序は実装に依存します-挿入の順序やその他の制御が困難な要因(同様に)。

[編集]私はvalueSet()最初に書いたが、もちろんentrySet()実際はその答えである。


36

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およびStreamsを使用):

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

forEachOrderedforEachストリーム?forEach(定義されている場合)の出会いの順序をたどるとして自然の中で本質的に非決定的ではありませんforEachOrderedありません。したがってforEach、注文が保持されることは保証されません。また、チェックこれを多くのため。


33

Java 8:

ラムダ式を使用できます。

myMap.entrySet().stream().forEach((entry) -> {
    Object currentKey = entry.getKey();
    Object currentValue = entry.getValue();
});

詳細については、こちらに従ってください


@injecteer:ラムダ式の動機のようです
humblerookie 2014

9
マップを反復処理するだけの場合は、ストリームは必要ありません。myMap.forEach( (currentKey,currentValue) -> /* action */ );はるかに簡潔です。
Holger

29

Java 1.4でこれを試してください:

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

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

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

  //...
}

26

地図では1オーバーの繰り返しができkeys、および/またはvaluesおよび/またはboth (e.g., entrySet) 同様の1興味IN_によって異なります。

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

_さらに、HashMapを反復処理するには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);
}

24

Java 8で最もコンパクト:

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

21

一般的な型なしマップがある場合は、以下を使用できます。

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

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

17

JavaでMapインターフェースを実装するオブジェクトがあり、その中に含まれるすべてのペアを反復処理したい場合、マップを通過する最も効率的な方法は何ですか?

キーをループする効率がアプリの優先事項でMapある場合は、キーを希望の順序で維持する実装を選択します。

要素の順序は、インターフェイスにある特定のマップ実装に依存しますか?

そのとおり。

  • Map特定の反復順序を約束する実装もあれば、そうしない実装もあります。
  • の実装でMapは、キーと値のペアの順序が異なります。

MapJava 11にバンドルされているさまざまな実装を要約して作成したこの表を参照してください。特に、反復順序の列に注目してください。クリック/タップしてズームします。

Java 11のマップ実装の表、それらの機能の比較

順序を維持する4つのMap実装があることがわかります。

  • TreeMap
  • ConcurrentSkipListMap
  • LinkedHashMap
  • EnumMap

NavigableMap インターフェース

それらの2つはNavigableMapインターフェースを実装します:TreeMapConcurrentSkipListMap

古いSortedMapインターフェイスは、新しいNavigableMapインターフェイスに実質的に取って代わられました。ただし、古いインターフェースのみを実装するサードパーティの実装が見つかる場合があります。

自然秩序

あなたがしたい場合はMap、そのペアがキー、使用の「自然順」で配置され続けていますTreeMapConcurrentSkipListMap。「自然順序」という用語は、キーの実装のクラスを意味しますComparable。によって返される値compareToメソッド、並べ替えの比較に使用されます。

カスタムオーダー

並べ替え順序の維持に使用するキーのカスタム並べ替えルーチンを指定する場合Comparatorは、キーのクラスに適した実装を渡します。TreeMapまたはを使用してConcurrentSkipListMap、を渡しますComparator

元の広告掲載オーダー

マップのペアを、マップに挿入したときの元の順序で保持する場合は、を使用しますLinkedHashMap

列挙型定義の順序

DayOfWeekまたはMonthキーとして列挙型を使用している場合は、EnumMapクラスを使用します。このクラスは非常に少ないメモリを使用して非常に高速に実行するように高度に最適化されているだけでなく、列挙型によって定義された順序でペアを維持します。たとえばDayOfWeek、のキーはDayOfWeek.MONDAY反復時に最初に見つかり、キーはDayOfWeek.SUNDAY最後なります。

その他の考慮事項

Map実装を選択する際には、以下も考慮してください。

  • NULL。一部の実装では、キーや値としてNULLを禁止/受け入れます。
  • 並行性。スレッド間でマップを操作する場合は、並行性をサポートする実装を使用する必要があります。または、マップをCollections::synchronizedMap(あまり好ましくない)でラップします。

これらの考慮事項はどちらも、上の図の表で説明されています。


パーティーにも遅い回答についての遅いコメント(ただし、非常に有益です)。言及EnumMapしたのは初めてです。聞いたのは初めてです。これが役立つ場合はおそらく多くあります。
user991710

15

順序は常に特定のマップ実装に依存します。Java 8を使用すると、次のいずれかを使用できます。

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

または:

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

結果は同じになります(同じ順序)。同じ順序で取得できるように、マップに対応するentrySet。2つ目は、ラムダを使用できるため便利です。たとえば、5より大きいIntegerオブジェクトのみを印刷する場合は、次のようにします。

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


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

14

Java 8を使用:

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

13

あなたはジェネリックを使用してそれを行うことができます:

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

12

Mapに対する効果的な反復ソリューションは、Java 5からJava 7までの「for each」ループです。ここでは次のようになります。

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

Java 8以降では、ラムダ式を使用してマップを反復できます。拡張された「forEach」です

phnMap.forEach((k,v) -> System.out.println("Key: " + k + " Value: " + v));

ラムダの条件を記述したい場合は、次のように記述できます。

phnMap.forEach((k,v)->{
    System.out.println("Key: " + k + " Value: " + v);
    if("abc".equals(k)){
        System.out.println("Hello abc");
    }
});

10
           //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();

            }

10

これを行う方法はたくさんあります。以下にいくつかの簡単な手順を示します。

次のような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));
}

9
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));
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.