[java] '지도'의 각 항목을 효율적으로 반복하는 방법은 무엇입니까?


Answers

다른 답변을 요약하고 내가 아는 것과 결합하기 위해이 작업을 수행하는 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. 키 세트 및 반복기 사용

    long i = 0;
    Iterator<Integer> itr2 = map.keySet().iterator();
    while (itr2.hasNext()) {
        Integer key = itr2.next();
        i += key + map.get(key);
    }
    
  6. forMap.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. Apache Collections IterableMap 사용하기

    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

모든 테스트는 GitHubGitHub .

Question

Java에서 Map 인터페이스를 구현하는 객체가 있고 그 안에 포함 된 모든 쌍을 반복하고 싶다면지도를 통과하는 가장 효율적인 방법은 무엇입니까?

요소의 순서는 인터페이스에 대한 특정 맵 구현에 따라 결정됩니까?




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



그것은 OP 질문에 대한 답변이 아니지만이 페이지를 찾는 다른 사람들에게 유용 할 수 있습니다.

키가 아닌 값만 필요하면 다음을 수행 할 수 있습니다.

Map<Ktype, Vtype> myMap = [...];
for (Vtype v: myMap.values()) {
  System.out.println("value: " + v);
}

Ktype , Vtype 은 의사 코드입니다.




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

            }



이를 수행하는 올바른 방법은 허용 된 답변을 가장 효율적으로 사용하는 것입니다. 다음 코드는 조금 더 깨끗해 보입니다.

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



람다 식 자바 8

Java 1.8 (Java 8)에서는 Iterable 인터페이스의 반복자와 비슷한 Aggregate 연산 ( 스트림 연산 )의 forEach 메소드를 사용하면 훨씬 쉽게 처리 할 수 ​​있습니다.

아래 문장을 코드에 복사하고 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 Docs에 대한 문서 링크 포함. 람다 에 대한 자세한 내용은이 link 로 이동해야하며 집계 연산을 읽어야하며 Spliterator에 대해서는이 link 로 이동 link .




일반적인 유형화되지 않은 맵이있는 경우 다음을 사용할 수 있습니다.

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



Java 8에서는 link 을 허용하는 forEach 메서드가 있습니다. stream 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);
        });

스트림의 이점은 우리가 원할 경우 쉽게 병렬화 될 수 있다는 것입니다. 위의 stream() 대신에 parallelStream() 을 사용하기 만하면됩니다.




제네릭을 사용하여 할 수 있습니다.

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) 각 루프마다 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 사용하기

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 사용하기

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

75 밀리 초

나는 this link .




예, 순서는 특정 Map 구현에 따라 다릅니다.

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



자바 1.4에서 이것을 사용해보십시오 :

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

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

  System.out.println(entry.getKey() + "/" + entry.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();
  // ...
}



Java 8 :

람다 식을 사용할 수 있습니다.

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

자세한 내용은 다음을 참조 this .




순서는 항상 특정 맵 구현에 따라 다릅니다. Java 8을 사용하면 다음 중 하나를 사용할 수 있습니다.

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

또는:

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

결과는 동일합니다 (동일한 순서). 동일한 순서를 얻으므로 entrySet은 맵에 의해 뒷받침됩니다. The second one is handy as it allows you to use lambdas, eg if you want only to print only Integer objects that are greater than 5:

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

The code below shows iteration through LinkedHashMap and normal HashMap (example). You will see difference in the order:

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,




Related