louis amoros louis amoros - 6 months ago 53
Java Question

Java 8 stream Map<Long, List<MyClass>> to Map<Long, Set<Long>>

I would like to convert (using Java 8 stream) a

Map<Long, List<MyClass>>
in a
Map<Long, Set<Long>>
where the
Set<Long>
represents the
id
of each
MyClass
of the
List
.

I have tried:

myFirstMap.entrySet().stream()
.map(e -> e.getValue().stream()
.map(MyClass::getId)
.collect(Collectors.toSet()))


But I cannot see how to get the result.

Answer

You are mapping instances of Map.Entry to Set<Long> instances which implies loosing track of the original map’s keys which makes it impossible to collect them into a new map having the same keys.

The first option is to map the Map.Entry<Long, List<MyClass>> instances to Map.Entry<Long, Set<Long>> instances and then collect the entries to a new map:

Map<Long, Set<Long>> result=
    myFirstMap.entrySet().stream()
        .map(e -> new AbstractMap.SimpleImmutableEntry<>(e.getKey(),
               e.getValue().stream().map(MyClass::getId).collect(Collectors.toSet())))
        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

The alternative is to fuse the map and collect step into one, to do the transformation right in the value function provided to the toMap collector:

Map<Long, Set<Long>> result=
    myFirstMap.entrySet().stream().collect(Collectors.toMap(
        Map.Entry::getKey,
        e -> e.getValue().stream().map(MyClass::getId).collect(Collectors.toSet())));

This way, you avoid creating new Map.Entry instances and get more concise code, however, loose flexibility as you can’t chain additional stream operations in-between.