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
, соответственно.