10. Сгруппировать названия книг по авторам
Условие задачи:
Дана коллекция объектов Book, где:
author— имя автора;names— список названий книг.
Необходимо:
получить
Map<String, List<String>>, где ключ — автор, а значение — список всех названий его книг;дополнительно получить для каждого автора только уникальные названия книг.
Код:
public class Main {
private record Book(String author, List<String> names) {
}
public static void main(String[] args) {
Set<Book> books = Set.of(
new Book("Author1", List.of("Name1")),
new Book("Author1", List.of("Name2")),
new Book("Author2", List.of("Name3")),
new Book("Author2", List.of("Name4", "Name3")),
new Book("Author3", List.of("Name5"))
);
}
}
Спойлеры к решению
Подсказки
author через Collectors.groupingBy().💡 У каждого
Book хранится список названий, поэтому вложенные списки нужно развернуть.💡 Для этого можно использовать
Collectors.flatMapping().💡 Для обычного результата собирай названия в
List, а для уникального — в Set.Решение
- Список названий книг по каждому автору:
Map<String, List<String>> booksByAuthor = books.stream()
.collect(Collectors.groupingBy(
Book::author,
Collectors.flatMapping(
book -> book.names().stream(),
Collectors.toList()
)
));
groupingBy() группирует объекты Book по автору:
Book::author
А flatMapping() разворачивает все списки names внутри одной группы в единый поток названий:
book -> book.names().stream()
Для приведённых данных результат будет содержать:
Author1 -> [Name1, Name2]
Author2 -> [Name3, Name4, Name3]
Author3 -> [Name5]
- Уникальные названия книг по каждому автору:
Map<String, Set<String>> uniqueBooksByAuthor = books.stream()
.collect(Collectors.groupingBy(
Book::author,
Collectors.flatMapping(
book -> book.names().stream(),
Collectors.toSet()
)
));
Теперь названия собираются в Set, поэтому повторяющиеся значения исключаются:
Author1 -> [Name1, Name2]
Author2 -> [Name3, Name4]
Author3 -> [Name5]
Если используется Java 8, где Collectors.flatMapping() ещё нет, ту же задачу можно решить через toMap():
Map<String, List<String>> booksByAuthor = books.stream()
.collect(Collectors.toMap(
Book::author,
book -> new ArrayList<>(book.names()),
(left, right) -> {
left.addAll(right);
return left;
}
));
Временная сложность — O(m), где m — общее количество названий книг во всех объектах Book. Дополнительная память также зависит от количества собранных названий.