Matt Passell - 2 years ago 76
Java Question

# Using Java 8 lambdas/transformations to combine and flatten two Maps

I have two maps:

• Map<A, Collection<B>> mapAB

• Map<B, Collection<C>> mapBC

I would like to transform them into a
Map<A, Collection<C>> mapAC
and I'm wondering if there's a smooth way to do that with lambdas and transformations. In my particular case, the collections are all sets, but I'd like to solve the problem for collections in general.

One thought I had was to first combine the two maps into a
Map<A, Map<B, Collection<C>>>
and then flatten it, but I'm open to any approach.

Data notes:
B
should only occur in the value collection associated with one
A
, and the same is true for
mapBC
(a given
C
is only mapped to from one
B
). As a result, there should only be one path from a given
A
to a given
C
, although there may be
A -> B
mappings for which there are no
B -> C
mappings and there may be
B -> C
mappings for which there are no corresponding
A -> B
mappings. These orphans simply don't appear in the resulting
mapAC
.

For the sake of comparison, here's an example of a purely imperative approach to the same problem:

Map<A, Collection<C>> mapAC = new HashMap<>();

for (Entry<A, Collection<B>> entry : mapAB.entrySet()) {
Collection<C> cs = new HashSet<>();

for (B b : entry.getValue()) {
Collection<C> origCs = mapBC.get(b);
if (origCs != null) {
}
}

if (!cs.isEmpty()) {
mapAC.put(entry.getKey(), cs);
}
}

You didn't specify what you would want to do if some b from the first map don't exist in the second map, so this may not be exactly what you are looking for.

mapAB.entrySet().stream()
.filter(e -> e.getValue().stream().anyMatch(mapBC::containsKey))
.collect(toMap(
Map.Entry::getKey,
e->e.getValue().stream()
.filter(mapBC::containsKey)
.map(mapBC::get)
.flatMap(Collection::stream)
.collect(toList())
));
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download