I have an iteraror where in every iteration I´m creating a new map
Map<String, List<String>>
Now I would like to merge in every iteration the last emitted map with the new one.
If I send a list of items to getMap
{"a","a","b"}
I expect to receive a map of
["a",{"foo:a", "foo:a"}, "b",{"foo:b"}]
I try to use reduce function, but because putall only works if I use multimap and not map, is not a good option.
Here my code
public Map<String, List<String>> getMap(List<String> items){
return items().stream()
.map(item -> getNewMap(item) --> Return a Map<String, List<String>>
.reduce(new HashMap<>(), (o, p) -> {
o.putAll(p);
return o;
});
}
public Map<String, List<String>> getNewMap(String item){
Map<String, List<String>> map = new HashMap<>();
map.put(item, Arrays.asList("foo:" + item));
return map;
}
I´m looking for a no verbose way to do it.
What you want is to flat map each intermediate map to its entries and make a single map out of that.
In the following code, each item is mapped to its corresponding map. Then, each map is flat mapped to its entries and the Stream is collected into a map.
public static void main(String[] args) {
System.out.println(getMap(Arrays.asList("a", "a", "b")));
// prints "{a=[foo:a, foo:a], b=[foo:b]}"
}
public static Map<String, List<String>> getMap(List<String> items) {
return items.stream()
.map(item -> getNewMap(item))
.flatMap(m -> m.entrySet().stream())
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(l1, l2) -> { List<String> l = new ArrayList<>(l1); l.addAll(l2); return l; }
));
}
public static Map<String, List<String>> getNewMap(String item) {
Map<String, List<String>> map = new HashMap<>();
map.put(item, Arrays.asList("foo:" + item));
return map;
}
In the case of multiple keys, this appends each list together.
Whenever you want to get a Map<…, List<…>> from a stream, you should first check, how the groupingBy collector fits in. In its simplest form, it receives a grouping function which determines the keys of the resulting map and will collect all elements of a group into a list. Since you want the prefix "foo:" prepended, you’ll have to customize this group collector by inserting a mapping operation before collecting the items into a list:
public static Map<String, List<String>> getMap(List<String> items) {
return items.stream().collect(Collectors.groupingBy(
Function.identity(),
Collectors.mapping("foo:"::concat, Collectors.toList())));
}
The classification function itself is as trivial as the identity function, as you want all equal elements building one group.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With