I have structure map of maps like:
Map<Center, Map<Product, Value>> given
and I want to get
Map<Product, Map<Center, Value>> result
I've used Java streams
Map<Product, Map<Center, Value>> result = given.entrySet().stream()
.flatMap(entry -> entry.getValue()
.entrySet().stream()
.map(e -> Triple(entry.getKey(), e.getKey(), e.getValue())))
.collect(Collectors.groupingBy(Triple::getProduct,
Collectors.toMap(Triple::getCenter, Triple::getValue)));
where Triple
is simple value class. My questions is if it is possible to do it functional without using additional classes like Triple
or e.g. Table
from guava?
Unfortunately, if you want to proceed with your stream approach it's unavoidable to create some type of intermediate object i.e. Triple
, or AbstractMap.SimpleEntry
or any other type applicable.
You're essentially looking for something like C#'s anonymous types i.e. you could just map to
new { k1 = entry.getKey(), k2 = e.getKey(), k3 = e.getValue()) }
and then immediately access those in the groupingBy
and toMap
phase.
Java has something similar but not quite i.e. you could do:
Map<Product, Map<Center, Value>> result =
given.entrySet()
.stream()
.flatMap(entry -> entry.getValue()
.entrySet().stream()
.map(e -> new Object() {
Center c = entry.getKey();
Product p = e.getKey();
Value v = e.getValue();
}))
.collect(Collectors.groupingBy(o -> o.p, Collectors.toMap(o -> o.c, o -> o.v)));
credit goes to @shmosel.
The only benefit here being you don't need to predefine a custom class.