У меня есть объект Foo, который имеет ссылки на объекты Bar и Baz:
public class Foo {
private Bar bar;
private Baz baz;
public Foo(Bar bar, Baz baz) {
this.bar = bar;
this.baz = baz;
}
}
У меня есть List<Foo>, который я хотел бы преобразовать в Map. Я бы хотел, чтобы ключом был Bar, а значением - List<Baz>.
Я могу создать Map, где Bar является ключом, а значение - List<Foo>:
Map<Bar, List<Foo>> mapBarToFoos = foos.stream().collect(Collectors.groupingBy(Foo::getBar));
Я не знаю, как сделать последний шаг и превратить список значений в List<Baz>. Есть ли лямбда-преобразование для значения, которое я не вижу?




Я думаю ты хочешь
list.stream().collect(groupingBy(Foo::getBar,
mapping(Foo::getBaz, toList())));
Где getBaz - это «нисходящий сборщик», который преобразует сгруппированные Foo, затем еще один, который создает список.
Наконец-то пришлось попробовать - сработало как шарм. Другие были столь же мудры в своих советах, но вы были первым. Спасибо!
Чтобы заменить классический grouping на Map<Bar, List<Foo>>, вам нужно использовать метод, который позволяет изменять значения карты:
//Use the import to reduce the Collectors. redundancy
//import static java.util.stream.Collectors.*;
Map<Bar, List<Baz>> mapBarToFoos =
foos.stream().collect(groupingBy(Foo::getBar, mapping(Foo::getBaz, toList())));
//without you'll get
Map<Bar, List<Baz>> mapBarToFoos =
foos.stream().collect(Collectors.groupingBy(Foo::getBar, Collectors.mapping(Foo::getBaz, Collectors.toList())));
Вы близки, вам нужно будет поставить "нижний" коллектор для дальнейшего уточнения ваших критериев. в этом случае подход groupingBy вместе с нижележащим коллектором mapping является идиоматическим подходом, т.е.
list.stream().collect(groupingBy(Foo::getBar, mapping(Foo::getBaz, toList())));
По сути, это работает путем применения нижележащего сборщика mapping к результатам функции классификации (Foo::getBar).
в основном то, что мы сделали, - это сопоставили каждый объект Foo с Baz и поместили его в список.
Просто хотел показать здесь другой вариант, хотя и не такой читабельный, как подход groupingBy:
foos.stream()
.collect(toMap(Foo::getBar, v -> new ArrayList<>(singletonList(v.getBaz())),
(l, r) -> {l.addAll(r); return l;}));
Foo::getBar - это функция keyMapper для извлечения ключей карты.v -> new ArrayList<>(singletonList(v)) - это valueMapper
функция для извлечения значений карты.(l, r) -> {l.addAll(r); return l;} - это функция слияния, используемая для
объедините два списка, которые имеют одинаковое значение getBar.
Правильная идея, вам просто нужно передать нижний коллектор на
mapping