I have two maps like this:
map1 = new Map<String, MyObject>();
map2 = new Map<String, MyObject>();
MyObject {
Integer mark1;
Integer mark2;
}
What I want to do to is to merge the two maps into a map3
<String, MyObject>
like this:
- If
map1.place
is not in map2.place
, then I add the entry to map3
.
- same if
map2.place
is not in map1.place
, I add the entry to map3
.
- if
map1.place
is in map2.place
, then I add this entry:
map1.place, (map1.mark1, map2.mark2)
I have read about flatMap
, but I really have a hard time using it.
Any clue how to do this?
Thanks!!
Here is what I think would work
Map<String, MyObj> map3 = new HashMap<>(map1);
map2.forEach(
(key, value) -> map3.merge(key, value, (v1, v2) -> new MyObject(v1.mark1,v2.mark2))
);
The merge function is what is taking care of your scenario 3, in that if the key already exists, it creates a new MyObject with v1.mark1 and v2.mark2
It can be done using the Stream API
with the appropriate mergeFunction
as next:
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())
)
);
This concatenates entries of map1
followed by the entries of map2
, then convert everything as a Map
with a merge function that will use mark1
from the first value (the one from map1
) and mark2
from the second value (the one from map2
) in case of duplicate keys.
Or it could also be done using a different Supplier<Map>
that will propose a map that already contains the entries of map1
then we can focus only on adding the entries of map2
as next:
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)
)
);
Something like this should work.
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);
}
}
Incase of a simple merge you could use map3.putAll()
as explained in How can I combine two HashMap objects containing the same types?
In your case, you would probably have to write some custom logic,
First populate map3 with map1. Then Iterate the map3 to find any duplicates with map2 in which case you replace the entry with the map1.place, (map1.mark1, map2.mark2)
logic.
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;
}