Слияние двух карт с 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
}