Bagaimana cara saya mengulang secara efisien setiap entri dalam Java Map?

3303

Jika saya memiliki objek yang mengimplementasikan Mapantarmuka di Jawa dan saya ingin mengulangi setiap pasangan yang ada di dalamnya, apa cara paling efisien untuk menelusuri peta?

Apakah urutan elemen tergantung pada implementasi peta spesifik yang saya miliki untuk antarmuka?

iMack
sumber
38
Di Java 8 menggunakan Lambda Expression: stackoverflow.com/a/25616206/1503859
Nitin Mahesh
5
Java 8: stackoverflow.com/questions/46898/…
akhil_mittal

Jawaban:

5032
Map<String, String> map = ...
for (Map.Entry<String, String> entry : map.entrySet()) {
    System.out.println(entry.getKey() + "/" + entry.getValue());
}
ScArcher2
sumber
93
Jika Anda melakukannya, maka itu tidak akan berfungsi karena Entri adalah Kelas bersarang di Peta. java.sun.com/javase/6/docs/api/java/util/Map.html
ScArcher2
266
Anda dapat menulis impor sebagai "import java.util.Map.Entry;" dan itu akan berhasil.
jjujuma
55
@ Pureferret Satu-satunya alasan Anda mungkin ingin menggunakan iterator adalah jika Anda perlu memanggil removemetodenya. Jika itu masalahnya, jawaban lain ini menunjukkan kepada Anda bagaimana melakukannya. Jika tidak, loop yang ditingkatkan seperti yang ditunjukkan pada jawaban di atas adalah cara untuk pergi.
assylias
102
Saya percaya formulir Map.Entry lebih jelas daripada mengimpor kelas dalam ke namespace saat ini.
Josiah Yoder
31
Perhatikan bahwa Anda dapat menggunakan map.values()atau map.keySet()jika Anda ingin mengulang nilai atau kunci saja.
dguay
1216

Untuk meringkas jawaban lain dan menggabungkannya dengan apa yang saya ketahui, saya menemukan 10 cara utama untuk melakukan ini (lihat di bawah). Juga, saya menulis beberapa tes kinerja (lihat hasil di bawah). Sebagai contoh, jika kita ingin menemukan jumlah semua kunci dan nilai peta, kita dapat menulis:

  1. Menggunakan iterator dan 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. Menggunakan foreach dan Map.Entry

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

    final long[] i = {0};
    map.forEach((k, v) -> i[0] += k + v);
  4. Menggunakan keySet dan foreach

    long i = 0;
    for (Integer key : map.keySet()) {
        i += key + map.get(key);
    }
  5. Menggunakan keySet dan iterator

    long i = 0;
    Iterator<Integer> itr2 = map.keySet().iterator();
    while (itr2.hasNext()) {
        Integer key = itr2.next();
        i += key + map.get(key);
    }
  6. Menggunakan untuk dan Peta. Coba

    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. Menggunakan Java 8 Stream API

    final long[] i = {0};
    map.entrySet().stream().forEach(e -> i[0] += e.getKey() + e.getValue());
  8. Menggunakan paralel Java 8 Stream API

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

    long i = 0;
    MapIterator<Integer, Integer> it = iterableMap.mapIterator();
    while (it.hasNext()) {
        i += it.next() + it.getValue();
    }
  10. Menggunakan koleksi MutableMap of Eclipse (CS)

    final long[] i = {0};
    mutableMap.forEachKeyValue((key, value) -> {
        i[0] += key + value;
    });

Tes kinerja (mode = AverageTime, sistem = Windows 8.1 64-bit, Intel i7-4790 3.60 GHz, 16 GB)

  1. Untuk peta kecil (100 elemen), skor 0,308 adalah yang terbaik

    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. Untuk peta dengan 10.000 elemen, skor 37.606 adalah yang terbaik

    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. Untuk peta dengan 100000 elemen, skor 1184.767 adalah yang terbaik

    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

Grafik (tes kinerja tergantung pada ukuran peta)

Masukkan deskripsi gambar di sini

Tabel (tes kinerja tergantung pada ukuran peta)

          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

Semua tes ada di GitHub .

Viacheslav Vedenin
sumber
9
@ Viacheslav: jawaban yang sangat bagus. Hanya bertanya-tanya bagaimana Java8 apis dihalang-halangi, dalam patokan Anda, dengan menangkap lambdas ... (misalnya long sum = 0; map.forEach( /* accumulate in variable sum*/);menangkap sumpanjang, yang mungkin lebih lambat daripada mengatakan stream.mapToInt(/*whatever*/).summisalnya. Tentu saja Anda tidak selalu dapat menghindari negara menangkap, tetapi itu mungkin merupakan tambahan yang masuk akal ke bangku cadangan
GPI
17
8 tes Anda salah. itu mengakses variabel yang sama dari utas yang berbeda tanpa sinkronisasi. Ubah untuk AtomicIntegermemecahkan masalah.
talex
44
@ZhekaKozlov: lihat nilai kesalahan yang sangat besar. Pertimbangkan bahwa hasil tes x±emenyiratkan bahwa ada hasil dalam interval dari x-eke x+e, sehingga hasil tercepat ( 1184.767±332.968) berkisar dari 852ke 1518, sedangkan paling lambat kedua ( 1706.676±436.867) berjalan antara 1270dan 2144, sehingga hasilnya masih tumpang tindih secara signifikan. Sekarang lihat hasil paling lambat 3289.866±1445.564, yang menyiratkan perbedaan antara 1844dan 4735dan Anda tahu bahwa hasil tes ini tidak ada artinya.
Holger
8
Bagaimana dengan membandingkan 3 implementasi utama: HashMap, LinkedHashMap dan TreeMap?
Thierry
9
# 1 dan # 6 persis sama. Menggunakan whilevs. forloop bukan teknik yang berbeda untuk iterasi. Dan saya terkejut mereka memiliki variasi di antara mereka dalam tes Anda - yang menunjukkan bahwa tes tidak terisolasi dengan baik dari faktor eksternal yang tidak terkait dengan hal-hal yang ingin Anda uji.
ErikE
294

Di Java 8 Anda dapat melakukannya dengan bersih dan cepat menggunakan fitur lambdas baru:

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

Jenis kdan vakan disimpulkan oleh kompiler dan tidak perlu digunakan Map.Entrylagi.

Mudah sekali!

Koordinator
sumber
12
Bergantung pada apa yang ingin Anda lakukan dengan peta, Anda juga dapat menggunakan aliran API pada entri yang dikembalikan oleh map.entrySet().stream() docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html
Vitalii Fedorenko
1
Ini tidak akan berfungsi jika Anda ingin referensi variabel non-final yang dinyatakan di luar ekspresi lambda Anda dari dalam forEach () ...
Chris
7
@ Chris Benar. Ini tidak akan berfungsi jika Anda mencoba menggunakan variabel non-final yang efektif dari luar lambda.
Koordinator
243

Ya, urutannya tergantung pada implementasi Peta spesifik.

@ ScArcher2 memiliki sintaks Java 1.5 yang lebih elegan . Di 1.4, saya akan melakukan sesuatu seperti ini:

Iterator entries = myMap.entrySet().iterator();
while (entries.hasNext()) {
  Entry thisEntry = (Entry) entries.next();
  Object key = thisEntry.getKey();
  Object value = thisEntry.getValue();
  // ...
}
pkaeding
sumber
41
Lebih suka untuk-loop daripada sementara .. untuk (Entri Iterator = myMap.entrySet (). Iterator (); entri.hasNext ();) {...} Dengan sintaks ini ruang lingkup 'entri' dikurangi menjadi hanya untuk loop saja .
jai
8
@ jpredham Anda benar bahwa menggunakan forkonstruk for (Entry e : myMap.entrySet)tidak akan memungkinkan Anda untuk mengubah koleksi, tetapi contoh seperti @HanuAthena menyebutkan itu harus berfungsi, karena memberi Anda Iteratorruang lingkup. (Kecuali saya kehilangan sesuatu ...)
pkaeding
1
IntelliJ memberi saya kesalahan pada Entry thisEntry = (Entry) entries.next();: tidak mengenali Entry. Apakah itu kodesemu untuk sesuatu yang lain?
JohnK
1
@JohnK coba mengimpor java.util.Map.Entry.
pkaeding
1
Solusi ini tidak akan berfungsi jika Anda memiliki kunci integer dan kunci String.
140

Kode umum untuk iterasi pada peta adalah:

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

HashMapadalah implementasi peta kanonik dan tidak membuat jaminan (atau meskipun seharusnya tidak mengubah urutan jika tidak ada operasi yang bermutasi dilakukan di atasnya). SortedMapakan mengembalikan entri berdasarkan urutan alami kunci, atau Comparator, jika disediakan. LinkedHashMapakan mengembalikan entri dalam urutan penyisipan atau akses-urutan tergantung pada bagaimana hal itu telah dibangun. EnumMapmengembalikan entri dalam urutan kunci.

(Pembaruan: Saya pikir ini tidak lagi benar. ) Catatan, IdentityHashMap entrySetiterator saat ini memiliki implementasi khusus yang mengembalikan Map.Entrycontoh yang sama untuk setiap item di entrySet! Namun, setiap kali iterator baru dimajukan Map.Entrydiperbarui.

Tom Hawtin - tackline
sumber
6
EnumMap juga memiliki perilaku aneh ini bersama dengan IdentityHashMap
Premraj
1
"LinkedHashMap akan mengembalikan entri di [...] urutan akses [...]" ... jadi Anda mengakses elemen sesuai urutan Anda mengaksesnya? Entah tautologis, atau sesuatu yang menarik yang bisa menggunakan penyimpangan. ;-)
jpaugh
5
@jpaugh Hanya akses langsung ke LinkedHashMaphitungan. Melalui orang-orang iterator, spliterator, entrySet, dll, tidak mengubah pesanan.
Tom Hawtin - tackline
1
1. olahjika ? 2. Paragraf terakhir mungkin mendapat manfaat dari peningkatan.
Peter Mortensen
122

Contoh penggunaan iterator dan generik:

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();
  // ...
}
serg
sumber
14
Anda harus memasukkan Iteratorfor for untuk membatasi cakupannya.
Steve Kuo
@ SveveKuo Apa yang Anda maksud dengan "membatasi cakupannya"?
StudioWorks
12
@StudioWorks for (Iterator<Map.Entry<K, V>> entries = myMap.entrySet().iterator(); entries.hasNext(); ) { Map.Entry<K, V> entry = entries.next(); }. Dengan menggunakan konstruk tersebut, kami membatasi ruang lingkup (visibilitas variabel) entrieske for for.
ComFreek
3
@ComFreek Oh, begitu. Tidak tahu bahwa itu sangat berarti.
StudioWorks
102

Ini adalah pertanyaan dua bagian:

Bagaimana cara mengulangi entri Peta - @ ScArcher2 telah menjawabnya dengan sempurna.

Apa urutan iterasi - jika Anda hanya menggunakan Map, maka secara tegas, tidak ada jaminan pemesanan . Jadi Anda tidak harus benar-benar mengandalkan pemesanan yang diberikan oleh implementasi apa pun. Namun, SortedMapantarmuka meluas Mapdan memberikan apa yang Anda cari - implementasi akan memberikan urutan pengurutan yang konsisten.

NavigableMapadalah ekstensi lain yang berguna - ini adalah SortedMapdengan metode tambahan untuk menemukan entri dengan posisi yang dipesan di set kunci. Jadi berpotensi ini bisa menghapus kebutuhan untuk iterasi di tempat pertama - Anda mungkin dapat menemukan spesifik entryAnda setelah menggunakan higherEntry, lowerEntry, ceilingEntry, atau floorEntrymetode. The descendingMapMetode bahkan memberikan metode eksplisit membalik urutan traversal .

serg10
sumber
84

Ada beberapa cara untuk beralih di peta.

Berikut adalah perbandingan kinerja mereka untuk kumpulan data umum yang disimpan di peta dengan menyimpan sejuta pasangan nilai kunci di peta dan akan beralih di atas peta.

1) Menggunakan entrySet()untuk setiap loop

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

50 milidetik

2) Menggunakan keySet()untuk setiap loop

for (String key : testMap.keySet()) {
    testMap.get(key);
}

76 milidetik

3) Menggunakan entrySet()dan iterator

Iterator<Map.Entry<String,Integer>> itr1 = testMap.entrySet().iterator();
while(itr1.hasNext()) {
    Map.Entry<String,Integer> entry = itr1.next();
    entry.getKey();
    entry.getValue();
}

50 milidetik

4) Menggunakan keySet()dan iterator

Iterator itr2 = testMap.keySet().iterator();
while(itr2.hasNext()) {
    String key = itr2.next();
    testMap.get(key);
}

75 milidetik

Saya telah merujuk this link.

Darshan Patel
sumber
1
Waktu berjalan diambil dari artikel, yang tidak menggunakan Java Microbenchmarking Harness. Karenanya waktu tidak dapat diandalkan, karena kode dapat, misalnya, telah sepenuhnya dioptimalkan oleh kompiler JIT.
AlexB
59

Cara yang benar untuk melakukan ini adalah dengan menggunakan jawaban yang diterima karena merupakan yang paling efisien. Saya menemukan kode berikut terlihat sedikit lebih bersih.

for (String key: map.keySet()) {
   System.out.println(key + "/" + map.get(key));
}
Chris Dail
sumber
15
Ini bukan pendekatan terbaik, itu jauh lebih efisien untuk menggunakan entrySet (). Findbugs akan menandai kode ini (lihat findbugs.sourceforge.net/... )
Jeff Olson
6
@ JeffOlson meh, tidak juga. lookup peta adalah O (1) sehingga kedua loop berperilaku dengan cara yang sama. memang, itu akan sedikit lebih lambat dalam benchmark mikro tetapi saya kadang-kadang melakukan ini juga karena saya benci menulis argumen tipe berulang-ulang. Juga ini kemungkinan besar tidak akan pernah menjadi hambatan kinerja Anda, jadi lakukanlah jika itu membuat kode lebih mudah dibaca.
kritzikratzi
4
lebih detail: O(1) = 2*O(1)cukup banyak definisi notasi O besar. Anda benar dalam hal ini berjalan sedikit lebih lambat, tetapi dalam hal kompleksitas mereka sama.
kritzikratzi
2
dengan tabrakan atau tidak yang saya maksud itu tidak masalah jika Anda beberapa tabrakan, jelas itu cerita yang berbeda jika Anda hanya memiliki tabrakan. jadi Anda menjadi sangat kecil, tapi ya, apa yang Anda katakan itu benar.
kritzikratzi
2
@ Jeff Olson: komentar bahwa kompleksitas "Big O" tidak berubah, ketika hanya ada faktor konstan, yang benar. Namun, bagi saya itu penting apakah operasi membutuhkan satu atau dua jam. Yang lebih penting, harus ditekankan bahwa faktornya tidak 2 , karena iterasi pada entrySet()tidak sama sekali; itu hanya traversal linier dari semua entri. Sebaliknya, iterasi di atas keySet()dan melakukan pencarian per kunci dikenakan satu pencarian per kunci, jadi kita berbicara tentang pencarian nol vs pencarian n di sini, dan menjadi ukuran Map. Jadi faktornya jauh di luar 2...
Holger
57

FYI, Anda juga dapat menggunakan map.keySet()dan map.values()jika Anda hanya tertarik pada kunci / nilai peta dan bukan yang lain.

ckpwong
sumber
42

Dengan Java 8 , Anda dapat mengulangi Peta menggunakan ekspresi forEach dan lambda,

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

Dengan Eclipse Collections , Anda akan menggunakan forEachKeyValuemetode pada MapIterableantarmuka, yang diwarisi oleh MutableMapdan ImmutableMapantarmuka serta implementasinya.

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

Menggunakan kelas dalam anonim, Anda dapat menulis kode sebagai berikut:

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

Catatan: Saya pengendara untuk Eclipse Collections.

Donald Raab
sumber
37

Lambda Expression Java 8

Di Java 1.8 (Java 8) ini menjadi lebih mudah dengan menggunakan metode forEach dari operasi Agregat ( operasi Stream ) yang terlihat mirip dengan iterator dari Iterable Interface.

Cukup salin tempel pernyataan di bawah ini ke kode Anda dan ganti nama variabel HashMap dari hm ke variabel HashMap Anda untuk mencetak pasangan nilai kunci.

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.

Di bawah ini adalah contoh kode yang saya coba gunakan Ekspresi Lambda . Barang ini sangat keren. Harus dicoba.

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

Anda juga dapat menggunakan Spliterator untuk hal yang sama.

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

MEMPERBARUI


Termasuk tautan dokumentasi ke Oracle Docs. Untuk lebih lanjut tentang Lambda buka tautan ini dan harus membaca Operasi Agregat dan untuk Spliterator buka tautan ini .

Nitin Mahesh
sumber
36

Secara teori, cara paling efisien akan tergantung pada implementasi Peta. Cara resmi untuk melakukan ini adalah dengan menelepon map.entrySet(), yang mengembalikan satu set Map.Entry, yang masing-masing berisi kunci dan nilai ( entry.getKey()danentry.getValue() ).

Dalam implementasi istimewa, mungkin ada bedanya apakah Anda menggunakan map.keySet(), map.entrySet()atau sesuatu yang lain. Tapi saya tidak bisa memikirkan alasan mengapa ada orang yang menulis seperti itu. Kemungkinan besar tidak ada bedanya dengan kinerja apa yang Anda lakukan.

Dan ya, urutannya akan tergantung pada implementasinya - serta (mungkin) urutan penyisipan dan faktor-faktor sulit dikendalikan lainnya.

[Sunting] Saya menulis valueSet()awalnya tetapi tentu saja entrySet()sebenarnya jawabannya.

Leigh Caldwell
sumber
36

Java 8

Kami memiliki forEachmetode yang menerima ekspresi lambda . Kami juga punya aliran API. Pertimbangkan sebuah peta:

Map<String,String> sample = new HashMap<>();
sample.put("A","Apple");
sample.put("B", "Ball");

Iterate over keys:

sample.keySet().forEach((k) -> System.out.println(k));

Iterasikan lebih dari nilai:

sample.values().forEach((v) -> System.out.println(v));

Iterasi entri (Menggunakan forEach dan Streaming):

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

Keuntungan dengan stream adalah mereka dapat diparalelkan dengan mudah jika kita mau. Kami hanya perlu menggunakan parallelStream()di tempat di stream()atas.

forEachOrderedvs forEachdengan stream? Tidak forEachmengikuti urutan perjumpaan (jika didefinisikan) dan secara inheren bersifat non-deterministik sedangkan yang forEachOrderedtidak. Jadi forEachtidak menjamin bahwa pesanan akan disimpan. Periksa juga ini untuk lebih.

akhil_mittal
sumber
33

Java 8:

Anda dapat menggunakan ekspresi lambda:

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

Untuk informasi lebih lanjut, ikuti ini .

George Siggouroglou
sumber
@injecteer: Sepertinya motif ekspresi lambda
humblerookie
9
Anda tidak perlu streaming jika Anda hanya ingin mengulangi peta. myMap.forEach( (currentKey,currentValue) -> /* action */ );jauh lebih ringkas.
Holger
29

Coba ini dengan Java 1.4:

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

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

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

  //...
}
abods
sumber
26

Dalam Peta seseorang dapat mengulangi keysdan / atau valuesdan / atau both (e.g., entrySet) bergantung pada seseorang yang tertarik pada_ Suka:

  1. Iterate melalui keys -> keySet()peta:

    Map<String, Object> map = ...;
    
    for (String key : map.keySet()) {
        //your Business logic...
    }
  2. Iterate melalui values -> values()peta:

    for (Object value : map.values()) {
        //your Business logic...
    }
  3. Iterate melalui both -> entrySet()peta:

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

Selain itu, ada 3 cara berbeda untuk Iterate Through a HashMap. Mereka seperti di bawah ini__

//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);
}
Rupesh Yadav
sumber
24

Paling ringkas dengan Java 8:

map.entrySet().forEach(System.out::println);
bluehallu
sumber
21

Jika Anda memiliki Peta umum yang belum diketik, Anda dapat menggunakan:

Map map = new HashMap();
for (Map.Entry entry : ((Set<Map.Entry>) map.entrySet())) {
    System.out.println(entry.getKey() + "/" + entry.getValue());
}
dmunozfer
sumber
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);
        }
    }
}

ATAU

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();
        }
    }
}
Fathah Rehman P
sumber
17

Jika saya memiliki objek yang mengimplementasikan antarmuka Peta di Jawa dan saya ingin mengulangi setiap pasangan yang ada di dalamnya, apa cara paling efisien untuk menelusuri peta?

Jika efisiensi pengulangan tombol adalah prioritas untuk aplikasi Anda, maka pilih Mapimplementasi yang mempertahankan kunci dalam urutan yang Anda inginkan.

Apakah urutan elemen tergantung pada implementasi peta spesifik yang saya miliki untuk antarmuka?

Ya, tentu saja.

  • Beberapa Mapimplementasi menjanjikan urutan iterasi tertentu, yang lain tidak.
  • Implementasi Mapberbeda mempertahankan urutan berbeda dari pasangan kunci-nilai.

Lihat tabel ini yang saya buat merangkum berbagai Mapimplementasi yang dibundel dengan Java 11. Secara khusus, perhatikan kolom urutan iterasi . Klik / ketuk untuk memperbesar.

Tabel implementasi peta di Java 11, membandingkan fitur-fiturnya

Anda dapat melihat ada empat Mapimplementasi yang mempertahankan pesanan :

  • TreeMap
  • ConcurrentSkipListMap
  • LinkedHashMap
  • EnumMap

NavigableMap antarmuka

Dua dari mereka menerapkan NavigableMap antarmuka: TreeMap& ConcurrentSkipListMap.

Yang lebih tua SortedMapAntarmuka yang secara efektif digantikan oleh NavigableMapantarmuka yang lebih baru . Tetapi Anda mungkin menemukan implementasi pihak ketiga yang mengimplementasikan antarmuka yang lebih lama saja.

Tatanan alami

Jika Anda ingin Mappasangan yang mengatur pasangannya diatur oleh "urutan alami" kunci, gunakan TreeMapatau ConcurrentSkipListMap. Istilah "tatanan alam" berarti kelas dari kunci yang diterapkanComparable . Nilai yang dikembalikan oleh compareTometode ini digunakan untuk perbandingan dalam penyortiran.

Pesanan kustom

Jika Anda ingin menentukan rutin penyortiran khusus untuk kunci Anda yang akan digunakan dalam mempertahankan pesanan yang diurutkan, berikan Comparatorimplementasi yang sesuai dengan kelas kunci Anda. Gunakan salah satu TreeMapatauConcurrentSkipListMap , lewatComparator .

Urutan penyisipan asli

Jika Anda ingin pasangan peta Anda disimpan dalam urutan aslinya tempat Anda memasukkannya ke dalam peta, gunakan LinkedHashMap .

Urutan definisi-enum

Jika Anda menggunakan enum seperti DayOfWeekatau Monthsebagai kunci Anda, gunakan EnumMapkelas. Tidak hanya kelas ini sangat dioptimalkan untuk menggunakan memori sangat sedikit dan berjalan sangat cepat, ia mempertahankan pasangan Anda dalam urutan yang ditentukan oleh enum. Untuk DayOfWeek, misalnya, kunci DayOfWeek.MONDAYakan menjadi yang pertama ditemukan ketika iterasi, dan kunci DayOfWeek.SUNDAYakan menjadi yang terakhir.

Pertimbangan lainnya

Dalam memilih Mapimplementasi, pertimbangkan juga:

  • NULLs. Beberapa implementasi melarang / menerima NULL sebagai kunci dan / atau nilai.
  • Konkurensi. Jika Anda memanipulasi peta di utas, Anda harus menggunakan implementasi yang mendukung konkurensi. Atau bungkus peta dengan Collections::synchronizedMap(kurang disukai).

Kedua pertimbangan ini tercakup dalam tabel grafik di atas.

Basil Bourque
sumber
Terlambat mengomentari jawaban yang juga terlambat ke pesta (tapi sangat informatif). +1 dari saya untuk menyebutkan EnumMap, karena ini adalah pertama kalinya saya mendengarnya. Mungkin ada banyak kasus di mana ini mungkin berguna.
user991710
15

Pemesanan akan selalu tergantung pada implementasi peta spesifik. Menggunakan Java 8 Anda dapat menggunakan salah satu dari ini:

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

Atau:

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

Hasilnya akan sama (urutan yang sama). Entri yang didukung oleh peta sehingga Anda mendapatkan urutan yang sama. Yang kedua berguna karena memungkinkan Anda untuk menggunakan lambdas, misalnya jika Anda hanya ingin mencetak objek Integer yang lebih besar dari 5:

map.entrySet()
    .stream()
    .filter(e-> e.getValue() > 5)
    .forEach(System.out::println);

Kode di bawah ini menunjukkan iterasi melalui LinkedHashMap dan HashMap normal (contoh). Anda akan melihat perbedaan dalam urutan:

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,

Witold Kaczurba
sumber
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());    
    }
Fadid
sumber
14

Gunakan Java 8:

map.entrySet().forEach(entry -> System.out.println(entry.getValue()));
ABHAY JOHRI
sumber
13

Anda dapat melakukannya menggunakan obat generik:

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

Solusi berulang efektif atas Peta adalah loop 'untuk setiap' dari Java 5 hingga Java 7. Ini dia:

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

Dari Java 8 Anda dapat menggunakan ekspresi lambda untuk beralih di atas Peta. Ini adalah 'forEach' yang disempurnakan

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

Jika Anda ingin menulis persyaratan untuk lambda, Anda dapat menulisnya seperti ini:

phnMap.forEach((k,v)->{
    System.out.println("Key: " + k + " Value: " + v);
    if("abc".equals(k)){
        System.out.println("Hello abc");
    }
});
anandchaugule
sumber
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();

            }
Sajad NasiriNezhad
sumber
10

Ada banyak cara untuk melakukan ini. Di bawah ini adalah beberapa langkah sederhana:

Misalkan Anda memiliki satu Peta seperti:

Map<String, Integer> m = new HashMap<String, Integer>();

Kemudian Anda dapat melakukan sesuatu seperti di bawah ini untuk beralih ke elemen peta.

// ********** 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));
}
Utpal Kumar
sumber
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));
    }
}
Rupendra Sharma
sumber