Reputation: 33
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?
Upvotes: 3
Views: 466
Reputation: 56433
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.
Upvotes: 3
Reputation: 50716
Some things are easier done without streams:
Map<Product, Map<Center, Value>> result = new HashMap<>();
given.forEach((c, pv) -> pv.forEach((p, v) ->
result.computeIfAbsent(p, k -> new HashMap<>()).put(c, v)));
Upvotes: 7