Java 8 Lambda (группировка и сокращение за один шаг)

скажем у меня есть список из пары объектов

List<Pair<A,B>> listOfPairs = //some list of pairs ; 

Я хотел бы сгруппировать этот список в Map<A,Set<B>>.

В настоящее время я могу сделать это в два шага. Первый шаг группируется по A и возвращает a Map<A,Set<Pair<A,B>> следующим образом:

   Map<A,Set<Pair<A,B>> intermediateStep =   listOfPairs.stream().collect(Collectors.groupingBy((Pair::getLeft), Collectors.toSet()));

затем я передаю entryset карты выше и собираю их в желаемый конечный результат, главным образом путем сопоставления каждого объекта пары с его значением B и сбора их в набор:

 Map<A, Set<B>> finalResult= intermediateStep.entrySet().stream().collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue().stream().map(Pair::getRight).collect(Collectors.toSet())));

есть ли лучший способ достичь желаемого результата, возможно, за один шаг? Другими словами, промежуточный шаг, упомянутый выше, группируется по A, но правая сторона группировки возвращает весь объект Pair. Я хотел бы сгруппировать по A и указать a на набор связанных с ним Bs за один шаг.

(Я знаю это только потому, что я мог бы сделать это в один шаг, не значит, что я должен, потому что читаемость может пострадать, но мне любопытно.)

спасибо!

2 ответов


вы можете упростить код, передав mapping сборщик в groupingBy коллектор такой:

Map<A, Set<B>> collect = 
       listOfPairs.stream()
                  .collect(Collectors.groupingBy(Pair::getLeft, 
                                Collectors.mapping(Pair::getRight,
                                       Collectors.toSet())));

вы можете сделать это с помощью Map.computeIfAbsent:

Map<A, Set<B>> finalResult = new HashMap<>();
listOfPairs.forEach(pair -> finalResult.computeIfAbsent(
        pair.getLeft(), 
        k -> new HashSet<>())
    .add(pair.getRight()));

если вы хотите сохранить порядок вставки вы можете использовать LinkedHashMap и LinkedHashSet вместо HashMap и HashSet, соответственно.