Потоки Java: получать значения, сгруппированные по внутренней карте
У меня есть Map<A, Map<B, C>>
и я хочу получить от нее Map<B, List<C>>
с помощью потоков Java.
Я пытаюсь сделать это следующим образом:
public <A, B, C> Map<B, List<C>> groupsByInnerKey(Map<A, Map<B, C>> input) {
return input.values()
.stream()
.flatMap(it -> it.entrySet().stream())
.collect(Collectors.groupingBy(Map.Entry::getKey));
}
Что я ожидаю:
-
flatMap
дает Stream
of Map.Entry<B, C>
-
collect(Collectors.groupingBy(...))
принимает функцию, которая применяется к Map.Entry<B, C>
и возвращает B
, поэтому она собирает значения C
в List<C>
.
Но он не компилируется, буквально:
Нестатический метод не может ссылаться на статический контекст
на Map.Entry::getKey
в последней строке.
Может ли кто-нибудь объяснить, что не так, или что такое правильный способ добиться того, чего я хочу?
Ответы
Ответ 1
Ваш поток состоит из объектов Map.Entry
но вы хотите, чтобы вы собирали на самом деле значение записи, а не самой записи. С помощью вашего текущего кода вы получите Map<B, List<Map.Entry<B, C>>>
.
Таким образом, вы просто пропускаете вызов Collectors.mapping
. Этот сборщик будет отображать элемент Stream с заданной функцией mapper и собирать этот результат в нижестоящий контейнер. В этом случае картографом является Map.Entry::getValue
(поэтому возвращающее значение из записи карты), а сборщик нисходящего потока собирает в List
.
public <A, B, C> Map<B, List<C>> groupsByInnerKey(Map<A, Map<B, C>> input) {
return input.values()
.stream()
.flatMap(it -> it.entrySet().stream())
.collect(Collectors.groupingBy(
Map.Entry::getKey,
Collectors.mapping(Map.Entry::getValue, Collectors.toList())
));
}
Ответ 2
Конвейер потока возвращает Map<B, List<Map.Entry<B,C>>>
, а не Map<B, List<C>>
.
Чтобы получить Map<B, List<C>>
, вам нужно добавить mapping
которое будет отображать Map.Entry<B,C>
в C
:
return input.entrySet()
.stream()
.flatMap(it -> it.getValue().entrySet().stream())
.collect(Collectors.groupingBy(Map.Entry::getKey,Collectors.mapping(Map.Entry::getValue,Collectors.toList())));