Reputation: 15
I have the following maps:
Map<String, StringBuilder> map1 = new HashMap<>();
Map<String, StringBuilder> map2 = new HashMap<>();
StringBuilder sb11 = new StringBuilder("0004001:00:00;0004002:00:00;0004002:01:01;");
StringBuilder sb12 = new StringBuilder("0005001:00:00;0005002:00:00;0005002:01:01;");
StringBuilder sb13 = new StringBuilder("0007001:00:00;0007002:00:00;0007002:01:01;");
map1.put("0004", sb11);
map1.put("0005", sb12);
map1.put("0007", sb13);
StringBuilder sb21 = new StringBuilder("0004002:00:00;0004002:00:00;0004002:01:01;");
StringBuilder sb22 = new StringBuilder("0007002:00:00;0007002:00:00;0007002:01:01;");
StringBuilder sb23 = new StringBuilder("0008002:00:00;0008002:00:00;0008002:01:01;");
map2.put("0004", sb21);
map2.put("0007", sb22);
map2.put("0008", sb23);
On the basis of these maps, I need to obtain a result map that for identical keys in both maps above has a concatenation of values separated by "|".
For different keys also the condition must be met - if the key is present only in map1 then only the value is added, and if the key is present only in map2 then "|" should be added before the value. In short, I mean this result:
map1
0004 - 0004001:00:00;0004002:00:00;0004002:01:01;
0005 - 0005001:00:00;0005002:00:00;0005002:01:01;
0007 - 0007001:00:00;0007002:00:00;0007002:01:01;
map2
0004 - 0004002:00:00;0004002:00:00;0004002:01:01;
0007 - 0007002:00:00;0007002:00:00;0007002:01:01;
0008 - 0008002:00:00;0008002:00:00;0008002:01:01;
expected result map
0004 - 0004001:00:00;0004002:00:00;0004002:01:01;|0004002:00:00;0004002:00:00;0004002:01:01;
0005 - 0005001:00:00;0005002:00:00;0005002:01:01;
0007 - 0007001:00:00;0007002:00:00;0007002:01:01;|0007002:00:00;0007002:00:00;0007002:01:01;
0008 - |0008002:00:00;0008002:00:00;0008002:01:01;
I almost managed to find a solution but I have a problem with the case when the key only exists in map2, I have no idea how to change my code so that the "|" sign is added in front of the value.
How can I fix it?
My code:
public static void main(String args[]) {
Map<String, StringBuilder> map1 = new HashMap<>();
Map<String, StringBuilder> map2 = new HashMap<>();
StringBuilder sb11 = new StringBuilder("0004001:00:00;0004002:00:00;0004002:01:01;");
StringBuilder sb12 = new StringBuilder("0005001:00:00;0005002:00:00;0005002:01:01;");
StringBuilder sb13 = new StringBuilder("0007001:00:00;0007002:00:00;0007002:01:01;");
map1.put("0004", sb11);
map1.put("0005", sb12);
map1.put("0007", sb13);
StringBuilder sb21 = new StringBuilder("0004002:00:00;0004002:00:00;0004002:01:01;");
StringBuilder sb22 = new StringBuilder("0007002:00:00;0007002:00:00;0007002:01:01;");
StringBuilder sb23 = new StringBuilder("0008002:00:00;0008002:00:00;0008002:01:01;");
map2.put("0004", sb21);
map2.put("0007", sb22);
map2.put("0008", sb23);
//Merge maps
map2.forEach((key, value) -> map1.merge(key, value, (v1, v2) -> v1.append("|").append(v2)));
map1.entrySet().forEach(entry->{
System.out.println(entry.getKey() + " " + entry.getValue());
});
}
Result:
0007 0007001:00:00;0007002:00:00;0007002:01:01;|0007002:00:00;0007002:00:00;0007002:01:01;
0004 0004001:00:00;0004002:00:00;0004002:01:01;|0004002:00:00;0004002:00:00;0004002:01:01;
0005 0005001:00:00;0005002:00:00;0005002:01:01;
0008 0008002:00:00;0008002:00:00;0008002:01:01;
Upvotes: 0
Views: 202
Reputation: 40034
Well, here is what I came up with. It simply iterates over one map checking the keys and putting the appropriate values in the other map. If each map contains the same key, then put
, both in map1
separated by |
, otherwise, put the map2 key
and value
in map1
with the prefixed
with |
.
for(String key : map2.keySet()) {
if (map1.containsKey(key)) {
map1.put(key, map1.get(key).append("|").append(map2.get(key)));
} else {
map1.put(key, map2.get(key).insert(0, "|"));
}
}
map1.entrySet().forEach(System.out::println);
Prints
0007=0007001:00:00;0007002:00:00;0007002:01:01;|0007002:00:00;0007002:00:00;0007002:01:01;
0004=0004001:00:00;0004002:00:00;0004002:01:01;|0004002:00:00;0004002:00:00;0004002:01:01;
0005=0005001:00:00;0005002:00:00;0005002:01:01;
0008=|0008002:00:00;0008002:00:00;0008002:01:01;
If you want them sorted by key, then make map1
a TreeMap
Upvotes: 1
Reputation: 102822
merge
simply cannot do the job. merge
will only invoke that function if both map1
and map2
have the provided key; otherwise, if only one of the two maps has a mapping for that key, that mapping is just inserted, without modification - thus, no leading |
. There is no way to make merge
work differently, so you just cannot use it here. Get rid of it.
As usual, it's just simpler to read if you use lambdas only where they seem like a clear win, instead of as the universal hammer that is so good you want to use it for everything, including buttering your bread.
for (var entry : map2.entrySet()) {
map1
.computeIfAbsent(entry.getKey(), x -> new StringBuilder())
.append("|")
.append(entry.getValue());
}
Simple enough, and does precisely what you want.
If you really are hell bent on using that hammer to smear this slice of bread, the method you really want is compute
. You'll have to mess around with null
though, it's not going to be any prettier.
NB: collection.forEach
, as well as collection.stream.forEach
are bad code style - you lose local variable, control flow, and exception transparency, and you gain absolutely nothing whatsoever in trade. Why pick a strictly inferior option? If you find it acceptable to dump e.g. someList.forEach(System.out::println);
on a single line, I'm having a hard time imagining what kind of non-crazy argument you might care to provide for disallowing for (var v : someList) System.out.println(v);
, which is just as short, and deals with local vars, control flow, and checked exceptions much better. I've done you the service of removing that bit. As I said, use lambdas when they get you something tangible, such as the computeIfAbsent
above. That'd be far more convoluted without them.
Upvotes: 2