동일한 유형을 포함하는 두 개의 HashMap 객체를 결합하려면 어떻게해야합니까?


241

HashMap다음과 같이 정의 된 두 개의 객체 가 있습니다 .

HashMap<String, Integer> map1 = new HashMap<String, Integer>();
HashMap<String, Integer> map2 = new HashMap<String, Integer>();

또한 세 번째 HashMap객체가 있습니다.

HashMap<String, Integer> map3;

어떻게 병합 할 수 있습니다 map1map2에 함께 map3?


16
두 맵 모두에 키가 존재하는 경우 어떤 작업을 수행할지 명시하지 않았습니다.
Michael Scheper

답변:


344
map3 = new HashMap<>();

map3.putAll(map1);
map3.putAll(map2);

1
고맙습니다.지도를 반환하는 메소드를 사용하는 for 루프에서지도를 병합하고 다른지도에 병합하고 동일한 메소드 agian를 적용해야합니다. 이를 위해 putAll 메소드로 null 포인터 예외가 발생합니다. try / catch 블록을 사용하는 데 도움이되지 않습니다. 어떻게해야합니까? 나는 .... 등등 조건이있는 경우 크기가 == 오 후 putAll에 적용되지 않는 경우 다른 그것을 적용하는 것이 적용 오전
Mavin

1
NPE를 얻는다면 분명히 객체 중 하나를 올바르게 초기화하지 않은 것입니다. 캐치 블록에 스택 트레이스를 인쇄합니까? 따라서 문제 발생한 위치 를 알 수 있습니다 . 그러나 스택 추적을 포함하여 완전하고 정확한 코드를 게시하지 않으면 직접 추적해야합니다.
a_horse_with_no_name 23시 43 분

95
이 솔루션을 사용하면 두 맵에 키가 있으면 map2의 값이 유지되고 map1의 ​​값이 손실됩니다.
Michael Scheper

5
@ MichaelScheper : 다른 무엇을 기대합니까? 의 키는 Map정의에 따라 고유
a_horse_with_no_name

42
OPer가 무엇을 기대하는지 모르겠습니다. 어쩌면 그는 map1 값이 우선하거나 예외가 발생하거나 교차 정수에서 일부 '병합'연산이 수행되기를 기대합니다. 또는 이것은 초보자의 질문이므로 OPer가 고려하지 않은 경우입니다.이 경우 내 의견이 도움이 될 것입니다.
Michael Scheper

109

중복 키가 없거나 중복 키의 값 map2을 덮어 쓰려는 값을 알고 싶다면 map1간단히 쓸 수 있습니다.

map3 = new HashMap<>(map1);
map3.putAll(map2);

값을 결합하는 방법에 대해 더 많은 제어가 필요한 경우 Map.mergeJava 8에 추가 BiFunction된를 사용하여 사용자 제공 값을 사용하여 중복 키 값을 병합 할 수 있습니다. merge개별 키와 값에서 작동하므로 루프 또는을 사용해야합니다 Map.forEach. 여기서 중복 키에 대한 문자열을 연결합니다.

map3 = new HashMap<>(map1);
for (Map.Entry<String, String> e : map2.entrySet())
    map3.merge(e.getKey(), e.getValue(), String::concat);
//or instead of the above loop
map2.forEach((k, v) -> map3.merge(k, v, String::concat));

중복 키가없고 적용하려는 경우 AssertionError다음 을 throw하는 병합 기능을 사용할 수 있습니다 .

map2.forEach((k, v) ->
    map3.merge(k, v, (v1, v2) ->
        {throw new AssertionError("duplicate values for key: "+k);}));

이 특정 질문에서 한 걸음 물러 나면 Java 8 스트림 라이브러리는 toMapgroupingBy 수집기를 제공합니다 . 반복적으로 맵을 루프로 병합하는 경우 스트림을 사용하도록 계산을 재구성 할 수 있습니다. 이로 인해 코드를 명확하게하고 병렬 스트림과 동시 수집기를 사용하여 쉽게 병렬 처리 할 수 ​​있습니다.


46

Java 8 Stream API를 사용한 원 라이너 :

map3 = Stream.of(map1, map2).flatMap(m -> m.entrySet().stream())
       .collect(Collectors.toMap(Entry::getKey, Entry::getValue))

이 방법의 장점 중 하나는 병합 기능을 전달하는 기능입니다.이 기능은 동일한 키를 가진 값을 처리합니다.

map3 = Stream.of(map1, map2).flatMap(m -> m.entrySet().stream())
       .collect(Collectors.toMap(Entry::getKey, Entry::getValue, Math::max))

1
중복 키에 대해 IllegalStateException이 발생합니다
Arpit J.

1
@ArpitJ. 이것이 두 번째 변형의 요점입니다. 때로는 예외를 원하고 때로는 그렇지 않습니다.
Alex R

36

두 개의 맵을 병합하기위한 Java 8 대체 1- 라이너 :

defaultMap.forEach((k, v) -> destMap.putIfAbsent(k, v));

메소드 참조와 동일합니다.

defaultMap.forEach(destMap::putIfAbsent);

또는 세 번째 맵이 포함 된 원본 맵 솔루션에 대해서는 동일하지 않습니다.

Map<String, Integer> map3 = new HashMap<String, Integer>(map2);
map1.forEach(map3::putIfAbsent);

다음은 가능한 최소한의 중간 복사 작업을 수행 하는 Guava 를 사용하여 두 개의 맵을 불변의 빠른 맵으로 병합하는 방법입니다 .

ImmutableMap.Builder<String, Integer> builder = ImmutableMap.<String, Integer>builder();
builder.putAll(map1);
map2.forEach((k, v) -> {if (!map1.containsKey(k)) builder.put(k, v);});
ImmutableMap<String, Integer> map3 = builder.build();

두 맵에있는 값을 맵핑 기능과 결합해야하는 경우 Java 8과 함께 두 맵 병합을 참조하십시오 .


32

당신이 당신의 마지막지도에 대한 가변성이 필요하지 않은 경우,이 구아바의 ImmutableMap 그것과 BuilderputAll방법을 달리하는, 자바의 Map인터페이스 방법 , 체인 될 수있다.

사용 예 :

Map<String, Integer> mergeMyTwoMaps(Map<String, Integer> map1, Map<String, Integer> map2) {
  return ImmutableMap.<String, Integer>builder()
      .putAll(map1)
      .putAll(map2)
      .build();
}

물론이 방법은보다 일반적이며 varargs를 사용하고 putAll Maps인수 등을 반복 할 수 는 있지만 개념을 보여주고 싶었습니다.

또한, ImmutableMap과는 Builder몇 가지 한계를 가지고 (또는 어쩌면 특징?) :

  • 그들은 적대적입니다 ( NullPointerException지도에있는 키 또는 값이 null 인 경우 던져 )
  • 빌더는 중복 키를 허용하지 않습니다 ( IllegalArgumentException중복 키가 추가 된 경우 발생).



11

공통 키를 공유 할 수있는 두 개의 맵을 결합하는 일반적인 솔루션 :

내부 :

public static <K, V> void mergeInPlace(Map<K, V> map1, Map<K, V> map2,
        BinaryOperator<V> combiner) {
    map2.forEach((k, v) -> map1.merge(k, v, combiner::apply));
}

새로운지도를 반환 :

public static <K, V> Map<K, V> merge(Map<K, V> map1, Map<K, V> map2,
        BinaryOperator<V> combiner) {
    Map<K, V> map3 = new HashMap<>(map1);
    map2.forEach((k, v) -> map3.merge(k, v, combiner::apply));
    return map3;
}

2

다른지도에서지도를 만들 때 자주 사용하는 작은 스 니펫 :

static public <K, V> Map<K, V> merge(Map<K, V>... args) {
    final Map<K, V> buffer = new HashMap<>();

    for (Map m : args) {
        buffer.putAll(m);
    }

    return buffer;
}

2

HashMap<String, List<Integer>>두 해시 맵을 병합하고 동일한 키와 쌍을 이루는 요소를 잃지 않도록 하는 데 사용할 수 있습니다 .

HashMap<String, Integer> map1 = new HashMap<>();
HashMap<String, Integer> map2 = new HashMap<>();
map1.put("key1", 1);
map1.put("key2", 2);
map1.put("key3", 3);
map2.put("key1", 4);
map2.put("key2", 5);
map2.put("key3", 6);
HashMap<String, List<Integer>> map3 = new HashMap<>();
map1.forEach((str, num) -> map3.put(str, new ArrayList<>(Arrays.asList(num))));
//checking for each key if its already in the map, and if so, you just add the integer to the list paired with this key
for (Map.Entry<String, Integer> entry : map2.entrySet()) {
    Integer value = entry.getValue();
    String key = entry.getKey();
    if (map3.containsKey(key)) {
        map3.get(key).add(value);
    } else {
        map3.put(key, new ArrayList<>(Arrays.asList(value)));
    }
}
map3.forEach((str, list) -> System.out.println("{" + str + ": " + list + "}"));

산출:

{key1: [1, 4]}
{key2: [2, 5]}
{key3: [3, 6]}

2

매우 늦었지만 같은 문제가 있었을 때 내가 한 일을 공유하겠습니다.

Map<String, List<String>> map1 = new HashMap<>();
map1.put("India", Arrays.asList("Virat", "Mahi", "Rohit"));
map1.put("NZ", Arrays.asList("P1","P2","P3"));

Map<String, List<String>> map2 = new HashMap<>();
map2.put("India", Arrays.asList("Virat", "Mahi", "Rohit"));
map2.put("NZ", Arrays.asList("P1","P2","P4"));

Map<String, List<String>> collect4 = Stream.of(map1, map2)
                .flatMap(map -> map.entrySet().stream())
                .collect(
                        Collectors.toMap(
                                Map.Entry::getKey,
                                Map.Entry::getValue,
                                (strings, strings2) -> {
                                    List<String> newList = new ArrayList<>();
                                    newList.addAll(strings);
                                    newList.addAll(strings2);
                                    return newList;
                                }
                        )
                );
collect4.forEach((s, strings) -> System.out.println(s+"->"+strings));

그것은 다음과 같은 출력을 제공합니다

NZ->[P1, P2, P3, P1, P2, P4]
India->[Virat, Mahi, Rohit, Virat, Mahi, Rohit]

0
    HashMap<Integer,String> hs1 = new HashMap<>();
    hs1.put(1,"ram");
    hs1.put(2,"sita");
    hs1.put(3,"laxman");
    hs1.put(4,"hanuman");
    hs1.put(5,"geeta");

    HashMap<Integer,String> hs2 = new HashMap<>();
    hs2.put(5,"rat");
    hs2.put(6,"lion");
    hs2.put(7,"tiger");
    hs2.put(8,"fish");
    hs2.put(9,"hen");

    HashMap<Integer,String> hs3 = new HashMap<>();//Map is which we add

    hs3.putAll(hs1);
    hs3.putAll(hs2);

    System.out.println(" hs1 : " + hs1);
    System.out.println(" hs2 : " + hs2);
    System.out.println(" hs3 : " + hs3);

hs3을 인쇄 할 때 키 5에 대해 하나의 값만 얻습니다. 마지막으로 추가 된 값은 쥐입니다. ** [세트에는 복제 키를 허용하지 않는 속성이 있지만 값을 복제 할 수 있음]


0

방법 1 :지도를 목록에 넣고 조인

public class Test15 {
public static void main(String[] args) {

    Map<String, List<String>> map1 = new HashMap<>();
    map1.put("London", Arrays.asList("A", "B", "C"));
    map1.put("Wales", Arrays.asList("P1", "P2", "P3"));

    Map<String, List<String>> map2 = new HashMap<>();
    map2.put("Calcutta", Arrays.asList("Protijayi", "Gina", "Gini"));
    map2.put("London", Arrays.asList( "P4", "P5", "P6"));
    map2.put("Wales", Arrays.asList( "P111", "P5555", "P677666"));

    System.out.println(map1);System.out.println(map2);



    // put the maps in an ArrayList

    List<Map<String, List<String>>> maplist = new ArrayList<Map<String,List<String>>>();
    maplist.add(map1);
    maplist.add(map2);
    /*
<T,K,U> Collector<T,?,Map<K,U>> toMap(

                                  Function<? super T,? extends K> keyMapper,

                                  Function<? super T,? extends U> valueMapper,

                                  BinaryOperator<U> mergeFunction)
    */

 Map<String, List<String>> collect = maplist.stream()
    .flatMap(ch -> ch.entrySet().stream())
    .collect(
            Collectors.toMap(

            //keyMapper,

            Entry::getKey,

            //valueMapper
            Entry::getValue,

            // mergeFunction
     (list_a,list_b) -> Stream.concat(list_a.stream(), list_b.stream()).collect(Collectors.toList())

            ));



    System.out.println("Final Result(Map after join) => " + collect);
    /*
    {Wales=[P1, P2, P3], London=[A, B, C]}
{Calcutta=[Protijayi, Gina, Gini], Wales=[P111, P5555, P677666], London=[P4, P5, P6]}
Final Result(Map after join) => {Calcutta=[Protijayi, Gina, Gini], Wales=[P1, P2, P3, P111, P5555, P677666], London=[A, B, C, P4, P5, P6]}
*/

}//main


}

방법 2 : 노멀 맵 병합

public class Test15 {
public static void main(String[] args) {

    Map<String, List<String>> map1 = new HashMap<>();
    map1.put("London", Arrays.asList("A", "B", "C"));
    map1.put("Wales", Arrays.asList("P1", "P2", "P3"));

    Map<String, List<String>> map2 = new HashMap<>();
    map2.put("Calcutta", Arrays.asList("Protijayi", "Gina", "Gini"));
    map2.put("London", Arrays.asList( "P4", "P5", "P6"));
    map2.put("Wales", Arrays.asList( "P111", "P5555", "P677666"));

    System.out.println(map1);System.out.println(map2);




    /*
<T,K,U> Collector<T,?,Map<K,U>> toMap(

                                  Function<? super T,? extends K> keyMapper,

                                  Function<? super T,? extends U> valueMapper,

                                  BinaryOperator<U> mergeFunction)
    */


Map<String, List<String>> collect = Stream.of(map1,map2)
    .flatMap(ch -> ch.entrySet().stream())
    .collect(
            Collectors.toMap(

            //keyMapper,

            Entry::getKey,

            //valueMapper
            Entry::getValue,

            // mergeFunction
     (list_a,list_b) -> Stream.concat(list_a.stream(), list_b.stream()).collect(Collectors.toList())

            ));



    System.out.println("Final Result(Map after join) => " + collect);
    /*
    {Wales=[P1, P2, P3], London=[A, B, C]}
{Calcutta=[Protijayi, Gina, Gini], Wales=[P111, P5555, P677666], London=[P4, P5, P6]}
Final Result(Map after join) => {Calcutta=[Protijayi, Gina, Gini], Wales=[P1, P2, P3, P111, P5555, P677666], London=[A, B, C, P4, P5, P6]}

*/

}//main


}

0

아래 코드에서 설명한 것처럼 맵에 putAll 함수를 사용할 수 있습니다

HashMap<String, Integer> map1 = new HashMap<String, Integer>();
map1.put("a", 1);
map1.put("b", 2);
map1.put("c", 3);
HashMap<String, Integer> map2 = new HashMap<String, Integer>();
map1.put("aa", 11);
map1.put("bb", 12);
HashMap<String, Integer> map3 = new HashMap<String, Integer>();
map3.putAll(map1);
map3.putAll(map2);
map3.keySet().stream().forEach(System.out::println);
map3.values().stream().forEach(System.out::println);

0

아래 스 니펫은 둘 이상의지도를 가져와 결합합니다.

 private static <K, V> Map<K, V> combineMaps(Map<K, V>... maps) {
        if (maps == null || maps.length == 0) {
            return Collections.EMPTY_MAP;
        }

        Map<K, V> result = new HashMap<>();

        for (Map<K, V> map : maps) {
            result.putAll(map);
        }
        return result;
    }

데모 예제 링크.


-1

사용할 수 있습니다-addAll 메소드

http://download.oracle.com/javase/6/docs/api/java/util/HashMap.html

그러나 두 개의 해시 맵에 동일한 키가있는 경우 항상 첫 번째 해시 맵의 키 값을 두 번째 해시 맵의 키 값으로 대체하는이 문제가 있습니다.

보다 안전한 측면을 유지하려면 키 값을 변경하십시오. 키에 접두사 또는 접미사를 사용할 수 있습니다 (첫 번째 해시 맵의 경우 다른 접두사 / 접미사 및 두 번째 해시 맵의 경우 다른 접두사 / 접미사)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.