Câu hỏi Lặp lại thông qua HashMap [duplicate]


Có thể trùng lặp: 
Làm thế nào để có hiệu quả lặp qua mỗi mục trong một 'Bản đồ'?

Cách tốt nhất để lặp lại các mục trong một HashMap?


2833
2018-06-30 23:24


gốc


Tôi cần lấy các khóa và giá trị và thêm chúng vào một mảng đa chiều - burntsugar
Làm thế nào điều này có một điểm số cao hơn câu hỏi đó là một bản sao của? - immibis
Trong Java 8 sử dụng biểu thức Lambda: stackoverflow.com/a/25616206/1503859 - Nitin Mahesh
@immibis có lẽ vì rất nhiều người theo bản năng sử dụng HashMaps mà không xem xét việc triển khai bản đồ khác. Sau đó, khi họ chắc chắn gặp khó khăn cố gắng để lặp qua HashMap của họ, họ đấm "Iterate thông qua một HashMap" vào Google, dẫn họ thẳng ở đây. - Dean Wild


Các câu trả lời:


Lặp lại thông qua entrySet() như vậy:

public static void printMap(Map mp) {
    Iterator it = mp.entrySet().iterator();
    while (it.hasNext()) {
        Map.Entry pair = (Map.Entry)it.next();
        System.out.println(pair.getKey() + " = " + pair.getValue());
        it.remove(); // avoids a ConcurrentModificationException
    }
}

Đọc thêm về Map.


2842
2018-06-30 23:27



Mặc dù phong cách cũ, điều này sẽ giúp tránh ConcurrentModificationExceptions trên phong cách foreach mới trong các câu trả lời dưới đây. Ví dụ, bạn có thể loại bỏ thông qua trình lặp riêng biệt. - Benjamin Wootton
@ karim79 bạn nghĩ gì về cách sau: Map<Integer, Integer> map = new HashMap<Integer, Integer>(); for (Map.Entry<Integer, Integer> entry : map.entrySet()) { System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue()); } - fresh_dev
bằng cách gọi 'it.remove (); 'bạn đang làm trống bản đồ khiến nó không thể tái sử dụng được nếu bản đồ này là một biến lớp. Bạn có giải pháp nào không? - vimukthi
@ vimukthi bạn có ý nghĩa gì với giải pháp đó? Chỉ cần xóa it.remove(); hàng. - Danny
Cho (Map.Entry<String, Object> cursor : map.entrySet()) {...} cú pháp tốt hơn nhiều. - Chad Okere


Nếu bạn chỉ quan tâm đến các khóa, bạn có thể lặp qua keySet() của bản đồ:

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

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

Nếu bạn chỉ cần các giá trị, hãy sử dụng values():

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

Cuối cùng, nếu bạn muốn cả khóa và giá trị, hãy sử dụng entrySet():

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

Một lưu ý: nếu bạn muốn loại bỏ các mục giữa-iteration, bạn sẽ cần phải làm như vậy thông qua một Iterator (xem câu trả lời của karim79). Tuy nhiên, việc thay đổi giá trị của mục là OK (xem Map.Entry).


4130
2018-06-30 23:28



Vì vậy, làm thế nào để làm vòng lặp thông qua 2 bản đồ cùng một lúc? sử dụng phương thức entrySet? Tôi đã thử sử dụng && nhưng nó không hoạt động - DaMainBoss
Sử dụng hai trình lặp. Xem câu trả lời được chấp nhận để sử dụng ví dụ của trình lặp. - harto
Nó chỉ hiệu quả hơn để sử dụng mục nhập khi bạn cần cả khóa và giá trị. Nếu bạn chỉ cần một hoặc khác sau đó chỉ cần sử dụng một: stackoverflow.com/questions/3870064/… - rogerdpack
Một điểm quan trọng hơn, Set được trả về bởi keySet () và Collection được trả về bởi các giá trị () đều được bản đồ gốc sao lưu. Tức là, nếu bạn thực hiện bất kỳ sửa đổi nào trong chúng, chúng sẽ được phản ánh lại trong Bản đồ, tuy nhiên, cả hai đều không hỗ trợ các phương thức add () và addAll () tức là bạn không thể thêm khóa mới vào giá trị Set hoặc new trong Bộ sưu tập. - sactiw
Về việc lấy cả hai giá trị và khóa, nó không chỉ đơn giản để sử dụng foreach ví dụ và nhận giá trị bên trong vòng lặp, với value = map.get(key)? Hiệu suất của entrySet cao hơn? - Marco Sulla


Đã trích xuất từ ​​tham chiếu Làm thế nào để lặp lại bản đồ trong Java:

Có một số cách lặp qua một Map trong Java. Hãy xem xét các phương pháp phổ biến nhất và xem lại ưu điểm và nhược điểm của chúng. Vì tất cả các bản đồ trong Java thực hiện giao diện Bản đồ, các kỹ thuật sau đây sẽ làm việc cho bất kỳ việc triển khai bản đồ nào (HashMap, TreeMap, LinkedHashMap, Hashtable, v.v.)

Phương pháp # 1: Lặp lại các mục nhập bằng cách sử dụng vòng lặp For-Each.

Đây là phương pháp phổ biến nhất và thích hợp hơn trong hầu hết các trường hợp. Nó sẽ được sử dụng nếu bạn cần cả khóa và giá trị bản đồ trong vòng lặp.

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

Lưu ý rằng vòng lặp For-Each đã được giới thiệu trong Java 5, vì vậy phương thức này chỉ hoạt động trong các phiên bản mới của ngôn ngữ. Ngoài ra một vòng lặp For-Each sẽ ném NullPointerException nếu bạn cố gắng lặp qua một bản đồ rỗng, vì vậy trước khi lặp, bạn nên luôn kiểm tra các tham chiếu null.

Phương pháp # 2: Lặp lại các khóa hoặc giá trị bằng cách sử dụng vòng lặp For-Each.

Nếu bạn chỉ cần các khóa hoặc giá trị từ bản đồ, bạn có thể lặp qua keySet hoặc các giá trị thay vì entrySet.

Map<Integer, Integer> map = new HashMap<Integer, Integer>();

// Iterating over keys only
for (Integer key : map.keySet()) {
    System.out.println("Key = " + key);
}

// Iterating over values only
for (Integer value : map.values()) {
    System.out.println("Value = " + value);
}

Phương pháp này cho một lợi thế hiệu suất nhỏ hơn entrySet lặp lại (nhanh hơn khoảng 10%) và sạch hơn.

Phương pháp # 3: Lặp lại bằng cách sử dụng Iterator.

Sử dụng Generics:

Map<Integer, Integer> map = new HashMap<Integer, Integer>();
Iterator<Map.Entry<Integer, Integer>> entries = map.entrySet().iterator();
while (entries.hasNext()) {
    Map.Entry<Integer, Integer> entry = entries.next();
    System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
}

Không có Generics:

Map map = new HashMap();
Iterator entries = map.entrySet().iterator();
while (entries.hasNext()) {
    Map.Entry entry = (Map.Entry) entries.next();
    Integer key = (Integer)entry.getKey();
    Integer value = (Integer)entry.getValue();
    System.out.println("Key = " + key + ", Value = " + value);
}

Bạn cũng có thể sử dụng cùng một kỹ thuật để lặp lại keySet hoặc giá trị.

Phương pháp này có thể trông thừa, nhưng nó có những ưu điểm riêng của nó. Trước hết, đó là cách duy nhất để lặp qua bản đồ trong các phiên bản Java cũ hơn. Các tính năng quan trọng khác là nó là phương pháp duy nhất cho phép bạn loại bỏ các mục từ bản đồ trong khi lặp lại bằng cách gọi iterator.remove(). Nếu bạn cố gắng thực hiện điều này trong quá trình lặp lại cho mỗi lần, bạn sẽ nhận được "kết quả không thể đoán trước" theo Javadoc.

Từ quan điểm hiệu suất của chế độ xem, phương thức này tương đương với lặp lại cho mỗi lần.

Phương pháp # 4: Lặp lại các khóa và tìm kiếm các giá trị (không hiệu quả).

Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for (Integer key : map.keySet()) {
    Integer value = map.get(key);
    System.out.println("Key = " + key + ", Value = " + value);
}

Điều này có thể trông giống như một phương án thay thế sạch hơn cho phương pháp # 1, nhưng thực tế nó khá chậm và không hiệu quả khi nhận được các giá trị bằng một khóa có thể tốn thời gian (phương pháp này trong các triển khai Bản đồ khác nhau chậm hơn 20% -200% so với phương pháp # 1 ). Nếu bạn đã cài đặt FindBugs, nó sẽ phát hiện điều này và cảnh báo bạn về việc lặp lại không hiệu quả. Phương pháp này nên tránh.

Phần kết luận:

Nếu bạn chỉ cần khóa hoặc giá trị từ bản đồ, hãy sử dụng phương pháp # 2. Nếu bạn đang mắc kẹt với phiên bản Java cũ hơn (ít hơn 5) hoặc lập kế hoạch để loại bỏ các mục trong quá trình lặp, bạn phải sử dụng phương pháp # 3. Nếu không, hãy sử dụng phương pháp # 1.


740
2017-12-08 14:19



Cho phép thêm các caevet nhỏ, trong trường hợp ConcurrentMaps, lặp lại trên keySet() sẽ sụp đổ nói chung (không có đảm bảo các giá trị tồn tại cho các khóa được thu thập trước đó). Mặt khác, sử dụng các trình vòng lặp hoặc các mục nhập là an toàn (chúng luôn đề cập đến các đối tượng hiện có). - P Marecki
@arvind Phương pháp # 4 sẽ không hiệu quả như thế nào? Theo định nghĩa, gọi get() luôn luôn là O (1) cho một HashMap. Đó là định nghĩa của HashMap và người dùng đã yêu cầu một HashMap. Tôi không hiểu tại sao điều này được đánh giá cao như vậy. Nếu bạn định tham khảo liên kết của người khác, hãy chắc chắn rằng nó thực sự có ý nghĩa đối với câu hỏi được hỏi. - ohbrobig


Bạn có thể lặp qua các mục trong một Map bằng nhiều cách. Nhận mỗi khóa và giá trị như sau:

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

Hoặc bạn có thể lấy danh sách các khóa bằng

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

Nếu bạn chỉ muốn nhận tất cả các giá trị và không quan tâm đến các khóa, bạn có thể sử dụng:

Collection<?> values = map.values();

77
2018-06-30 23:43





for (Map.Entry<String, String> item : params.entrySet()) {
    String key = item.getKey();
    String value = item.getValue();
}

70
2017-07-23 01:28





Thông minh hơn:

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

55
2017-08-11 10:01



điều này thực sự phụ thuộc vào việc bạn có cần chìa khóa hay không. nếu không, sẽ hiệu quả hơn khi sử dụng entrySet () như hashCode () không được gọi. - icfantv
map.get (khóa) cho mỗi lần lặp lại không thông minh hơn - theo cách của nó chậm hơn - ComputerEngineer88
map.entrySet () trả về các mục đã chứa cả khóa và giá trị. Bằng cách này bạn không cần phải gọi hashCode () và tìm kiếm hàm băm trong quá trình lặp. - ComputerEngineer88
Cú pháp Java 8. Có thể vẫn không hoạt động để phát triển Android. "Android không có ý định tương thích 100% với bất kỳ phiên bản Java SE API nào, không phải 6 cũng không phải bất kỳ. ... JRE là Môi trường chạy Java trong khi JDK là Bộ phát triển Java. Đây là JDK mà bạn cần để phát triển ứng dụng Android cùng với SDK Android hiện tại.Dec 9, 2013 " nguồn - jasonleonhard


Phụ thuộc. Nếu bạn biết bạn sẽ cần cả khóa và giá trị của mỗi mục nhập, hãy đi qua entrySet. Nếu bạn chỉ cần các giá trị, thì có values() phương pháp. Và nếu bạn chỉ cần các phím, sau đó sử dụng keyset().

Một thực hành không tốt sẽ là lặp qua tất cả các khóa, và sau đó trong vòng lặp, luôn luôn làm map.get(key) để có được giá trị. Nếu bạn đang làm điều đó, thì tùy chọn đầu tiên tôi viết là dành cho bạn.


40
2018-06-30 23:29



Một điểm quan trọng hơn, Set được trả về bởi keySet () và Collection được trả về bởi các giá trị () đều được bản đồ gốc sao lưu. Tức là, nếu bạn thực hiện bất kỳ sửa đổi nào trong chúng, chúng sẽ được phản ánh lại trong Bản đồ, tuy nhiên, cả hai đều không hỗ trợ các phương thức add () và addAll () tức là bạn không thể thêm khóa mới vào giá trị Set hoặc new trong Bộ sưu tập. - sactiw