Слияние двух карт с Java 8

У меня есть две карты:

map1 = new Map<String, MyObject>();
map2 = new Map<String, MyObject>();

MyObject {
   Integer mark1;
   Integer mark2;
}

Что я хочу сделать, так это объединить две карты в map3 <String, MyObject> следующим образом:

  • Если map1.place не находится в map2.place, я добавляю запись в map3.
  • если map2.place не находится в map1.place, я добавляю запись в map3.
  • Если map1.place находится в map2.place, я добавляю эту запись:
    • map1.place, (map1.mark1, map2.mark2)

Я читал о flatMap, но мне действительно трудно его использовать. Любой ключ, как это сделать?
Благодарю!!

Ответ 1

Вот то, что я думаю, будет работать

Map<String, MyObj> map3 = new HashMap<>(map1);
map2.forEach(
    (key, value) -> map3.merge(key, value, (v1, v2) -> new MyObject(v1.mark1,v2.mark2))
);

Функция слияния - это то, что заботится о вашем сценарии 3: если ключ уже существует, он создает новый MyObject с v1.mark1 и v2.mark2

Ответ 2

Это можно сделать с помощью Stream API с соответствующим mergeFunction следующим образом:

Map<String, MyObject> map3 = Stream.of(map1, map2)
    .flatMap(map -> map.entrySet().stream())
    .collect(
        Collectors.toMap(
            Map.Entry::getKey,
            Map.Entry::getValue,
            (v1, v2) -> new MyObject(v1.getMark1(), v2.getMark2())
        )
    );

Это объединяет записи map1, за которыми следуют записи map2, затем преобразует все как Map с функцией слияния, которая будет использовать mark1 от первого значения (от map1) и mark2 от второго значения (от map2) в случае дублирования ключей.


Или это также можно сделать с помощью другого Supplier<Map>, который предложит карту, которая уже содержит записи map1, тогда мы можем сосредоточиться только на добавлении записей map2 следующим образом:

Map<String, MyObject> map3 = map2.entrySet()
    .stream()
    .collect(
        Collectors.toMap(
            Map.Entry::getKey,
            Map.Entry::getValue,
            (v1, v2) -> new MyObject(v1.getMark1(), v2.getMark2()),
            () -> new HashMap<>(map1)
        )
    );

Ответ 3

Нечто подобное должно работать.

Map<String, MyObject> result = new HashMap<String, MyObject>();

Set<String> allKeys = new HashSet<String>();
allKeys.addAll(map1.keySet());
allKeys.addAll(map2.keySet());
for(String key : allKeys){
    MyObject v1 = map1.get(key);
    MyObject v2 = map2.get(key);
    if(v1 != null && v2 == null){
        result.put(key, v1);
    }else if(v1 == null && v2 !=null){
        result.put(key, v2);
    } else {
        MyObject newObject = new MyObject(v1.mark1, v2.mark2); 
        result.put(key, newObject);
    }
}

Ответ 4

В случае простого слияния вы можете использовать map3.putAll(), как описано в Как я могу объединить два объекта HashMap, содержащих одинаковые типы?

В вашем случае вам, вероятно, придется написать какую-то собственную логику,

Сначала заполните map3 картой map1. Затем выполните итерацию map3, чтобы найти дубликаты с map2, и в этом случае вы заменяете запись логикой map1.place, (map1.mark1, map2.mark2).

MapMerge

public class MapMerge {

    public static void main(String []args){


        Map<String, MyObject> map1 = new HashMap<String, MyObject>();
        Map<String, MyObject> map2 = new HashMap<String, MyObject>();
        Map<String, MyObject> map3 = new HashMap<String, MyObject>();

        map3.putAll(map1);

        for(Entry<String, MyObject> entry:map2.entrySet()){         
            if (map3.containsKey(entry.getKey())){                  
                MyObject map3Obj = map3.get(entry.getKey());
                map3.put(
                    entry.getKey(), 
                    new MyObject(map3Obj.getMark1(),entry.getValue().getMark2())
                );
            }
        }
    }
}

MyObject

class MyObject{

    public MyObject(Integer m1, Integer m2){
        mark1 = m1;
        mark2 = m2;
    }

    public Integer getMark1() {
        return mark1;
    }
    public void setMark1(Integer mark1) {
        this.mark1 = mark1;
    }
    public Integer getMark2() {
        return mark2;
    }
    public void setMark2(Integer mark2) {
        this.mark2 = mark2;
    }
    Integer mark1;
    Integer mark2;
}

Ответ 5

Случай 1: дан список карт. Тогда присоединяйся к картам по ключу

    public class Test14 {

        public static void main(String[] args) {

            Map<String, List<Integer>> m1 = new HashMap<>();
            Map<String, List<Integer>> m2 = new HashMap<>();
            m1.put("a", List.of(1));
            m1.put("b", List.of(2, 3));
            m2.put("a", List.of(12, 115));
            m2.put("b", List.of(2, 5));
            m2.put("c", List.of(6));

            System.out.println("map1 => " + m1);
            System.out.println("map2 => " + m2);

            ArrayList<Map<String, List<Integer>>> maplist = new ArrayList<Map<String, List<Integer>>>();
            maplist.add(m1);
            //   map1 => {a=[1], b=[2, 3]}
            maplist.add(m2);
            //      map2 => {a=[12, 115], b=[2, 5], c=[6]}

            System.out.println("maplist => " + maplist);
         //    maplist => [{a=[1], b=[2, 3]}, {a=[12, 115], b=[2, 5], c=[6]}]


            //  flatmap does omitted {} 
            List<Entry<String, List<Integer>>> collect11 = 
                    maplist
                    .stream()
                    .flatMap(map -> map.entrySet().stream())
                    .collect(Collectors.toList());
            System.out.println(" collect11  => " + collect11);
            // collect11  => [a=[1], b=[2, 3], a=[12, 115], b=[2, 5], c=[6]]

            // That why we will use this flatmap


            Map<String, List<Integer>> map2 = maplist.stream()
            .flatMap(map -> map.entrySet().stream())

            .collect(
                    Collectors.toMap(
                            //keyMapper 
                            Map.Entry::getKey,


                            //valueMapper
                            Map.Entry::getValue,

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


                            )//tomap

                    );
//{a=[1, 12, 115], b=[2, 3, 2, 5], c=[6]}

            System.out.println("After joining the maps according the key  => " + map2);
            // After joining the maps according the key  => {a=[1, 12, 115], b=[2, 3, 2, 5], c=[6]}

            /*
             OUTPUT :

             After joining the maps according the key  => {a=[1, 12, 115], b=[2, 3, 2, 5], c=[6]}
             */

        }// main

    }