0

How to convert Map<X, Map<Y,Z>> to Map<Y, Map<X,Z>> using Java8 stream.

Input:

{A : {B : C, D : E}} // Here B and D are the Key of inner map for A key
{F : {B : G, D : H}} // Here B and D are the Key of inner map for F key

Output:

{B : {A : C, F : G}} // Here A and F are the Key of inner map for B key
{D : {A : E, F : H}} // Here A and F are the Key of inner map for D key

2 Answers2

0

Something like the following code could help:

public static <X, Y, Z> Map<Y, Map<X, Z>> convert(Map<X, Map<Y, Z>> map) {
    return map.entrySet().stream()
            .flatMap(e -> e.getValue().entrySet().stream()
                    .map(en -> new AbstractMap.SimpleEntry<>(en.getKey(),
                            new AbstractMap.SimpleEntry<>(e.getKey(), en.getValue()))))
            .collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey,
                    ent -> constructInnerMap(ent.getValue().getKey(), ent.getValue().getValue()),
                    (xzMap1, xzMap2) -> {
                        xzMap2.putAll(xzMap1);
                        return xzMap2;
                    }));
}

public static <X, Z> Map<X, Z> constructInnerMap(X x, Z z) {
    Map<X, Z> map = new HashMap<>();
    map.put(x, z);
    return map;
}
Naman
  • 27,789
  • 26
  • 218
  • 353
0

Using streams here might not be that trivial or even necessary. You'd basically have to first map X, Y and Z to tuples and then reconstruct the "inverted" map further downstream. This wouldn't be too hard to do but would probably not make it easier to read or increase performance.

Instead you could do something like the following to leverage lambdas as well as function interfaces:

<X, Y, Z> Map<Y, Map<X, Z>> invert(Map<X, Map<Y, Z>> map) {
    //create a target map
    Map<Y, Map<X, Z>> target = new HashMap<>();

    //loop over the outer and inner entry sets 
    map.entrySet().forEach(outer -> outer.getValue().entrySet().forEach(
        //put the entries into the target map as needed while creating new nested maps as needed
        inner -> target.computeIfAbsent(inner.getKey(), k -> new HashMap<>() )
                       .put(outer.getKey(), inner.getValue())
    ));

    return target;
}
Thomas
  • 87,414
  • 12
  • 119
  • 157