Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как сгруппировать элементы используя Stream
groupingBy() — это мощный collector в Stream API для группировки элементов по ключу. Это аналог SQL GROUP BY.
Базовая группировка
List<String> fruits = Arrays.asList("apple", "banana", "apricot", "blueberry");
Map<Character, List<String>> grouped = fruits.stream()
.collect(Collectors.groupingBy(s -> s.charAt(0)));
// Результат:
// {a=[apple, apricot], b=[banana, blueberry]}
Группировка объектов
public class Person {
private String name;
private int age;
private String department;
// getters, setters
}
List<Person> people = Arrays.asList(
new Person("Alice", 30, "IT"),
new Person("Bob", 30, "HR"),
new Person("Charlie", 25, "IT")
);
// Группируем по отделу
Map<String, List<Person>> byDept = people.stream()
.collect(Collectors.groupingBy(Person::getDepartment));
// {IT=[Alice, Charlie], HR=[Bob]}
Подсчёт элементов
// Количество людей в каждом отделе
Map<String, Long> deptCount = people.stream()
.collect(Collectors.groupingBy(
Person::getDepartment,
Collectors.counting()
));
// {IT=2, HR=1}
Суммирование
public class Product {
private String category;
private double price;
// getters, setters
}
List<Product> products = Arrays.asList(
new Product("Electronics", 1000),
new Product("Books", 20),
new Product("Electronics", 500)
);
// Сумма цены по категориям
Map<String, Double> totalByCategory = products.stream()
.collect(Collectors.groupingBy(
Product::getCategory,
Collectors.summingDouble(Product::getPrice)
));
// {Electronics=1500.0, Books=20.0}
Усреднение
// Средняя цена по категориям
Map<String, Double> avgByCategory = products.stream()
.collect(Collectors.groupingBy(
Product::getCategory,
Collectors.averagingDouble(Product::getPrice)
));
// {Electronics=750.0, Books=20.0}
Многоуровневая группировка
public class Employee {
private String name;
private String department;
private String position;
// getters
}
List<Employee> employees = Arrays.asList(
new Employee("Alice", "IT", "Developer"),
new Employee("Bob", "IT", "Manager"),
new Employee("Charlie", "HR", "Developer")
);
// Группируем сначала по отделу, потом по должности
Map<String, Map<String, List<Employee>>> nested = employees.stream()
.collect(Collectors.groupingBy(
Employee::getDepartment,
Collectors.groupingBy(Employee::getPosition)
));
// {IT={Developer=[Alice], Manager=[Bob]}, HR={Developer=[Charlie]}}
Строка вместо List
// Вместо списка объектов, получаем строку
Map<String, String> namesByDept = people.stream()
.collect(Collectors.groupingBy(
Person::getDepartment,
Collectors.mapping(
Person::getName,
Collectors.joining(", ")
)
));
// {IT=Alice, Charlie, HR=Bob}
Множество элементов (Set)
// Вместо List получаем Set
Map<String, Set<Person>> deptSet = people.stream()
.collect(Collectors.groupingBy(
Person::getDepartment,
Collectors.toSet()
));
Статистика
import java.util.IntSummaryStatistics;
// Статистика по зарплатам в отделах
Map<String, IntSummaryStatistics> stats = employees.stream()
.collect(Collectors.groupingBy(
Employee::getDepartment,
Collectors.summarizingInt(Employee::getSalary)
));
IntSummaryStatistics itStats = stats.get("IT");
System.out.println("Count: " + itStats.getCount());
System.out.println("Sum: " + itStats.getSum());
System.out.println("Average: " + itStats.getAverage());
System.out.println("Min: " + itStats.getMin());
System.out.println("Max: " + itStats.getMax());
Пользовательский collector
// Группируем и затем преобразуем результат
Map<String, Integer> countOfExpensive = products.stream()
.collect(Collectors.groupingBy(
Product::getCategory,
Collectors.collectingAndThen(
Collectors.filtering(
p -> p.getPrice() > 100,
Collectors.toList()
),
List::size
)
));
Условная группировка
// Группируем по условию (есть/нет)
Map<Boolean, List<Product>> expensive = products.stream()
.collect(Collectors.partitioningBy(p -> p.getPrice() > 500));
// {false=[Books], true=[Electronics, Electronics]}
Производительность
// Для больших данных лучше использовать параллельный Stream
Map<String, Long> result = products.parallelStream()
.collect(Collectors.groupingBy(
Product::getCategory,
Collectors.counting()
));
Сложный пример: Top N элементов по группе
import java.util.stream.Collectors;
// Берём top 2 самых дорогих товара в каждой категории
Map<String, List<Product>> topByCategory = products.stream()
.collect(Collectors.groupingBy(
Product::getCategory,
Collectors.collectingAndThen(
Collectors.toList(),
list -> list.stream()
.sorted(Comparator.comparingDouble(Product::getPrice).reversed())
.limit(2)
.collect(Collectors.toList())
)
));
Ключевые моменты
- groupingBy(keyMapper) — базовая группировка
- groupingBy(keyMapper, collector) — группировка с кастомным collector
- groupingBy(keyMapper, supplier, collector) — с кастомной Map
- Множественные уровни — nested groupingBy
- Collectors.counting() — количество элементов
- Collectors.summingInt/Long/Double() — сумма
- Collectors.averaging()* — среднее значение
- Collectors.joining() — объединение строк
- Collectors.toSet() — Set вместо List
- parallelStream() — параллельная обработка
Stream groupingBy — это мощный инструмент для трансформации и анализа данных с минимальным кодом.