Collectors.groupingBy Explicación detallada de las estadísticas de agrupación
- 1 lista para mapear
-
- 1.1 Agrupación usando groupingBy
-
- Agrupar por departamento
- Agrupar por clave personalizada
- agrupación multinivel
- Agrupe por departamento y encuentre la lista de ID
- Agrupar por departamento, Contar el número de personas
- Según agrupación de departamentos, encuentre el Conjunto de Sexo
- Según la agrupación de departamentos, encuentre el número de duplicados en Sexo
- 1.2 Usar particionamientoPor particionamiento
- 1.3 Usando toMap
- 2 Encuentra el máximo, mínimo, promedio y suma
Es muy importante poder utilizar con habilidad groupingBy, reduce y toMap en Collectors en el trabajo, porque estas funciones inteligentes pueden mejorar en gran medida la eficiencia del desarrollo, por lo que es urgente aprenderlas bien. Primero prepare una colección de Listas para realizar pruebas.
public static List<User> getUserList() {
List<User> users = new ArrayList<>();
users.add(new User("1", "name1", "Java组", 33, "男", new BigDecimal("25000"), true));
users.add(new User("2", "name2", "Java组", 31, "女", new BigDecimal("28000"), true));
users.add(new User("3", "name3", "前端组", 33, "男", new BigDecimal("18000"), true));
users.add(new User("4", "name4", "前端组", 25, "男", new BigDecimal("19000"), false));
users.add(new User("5", "name5", "QA组", 24, "女", new BigDecimal("15000"), true));
users.add(new User("6", "name6", "产品组", 34, "女", new BigDecimal("12000"), true));
return users;
}
1 lista para mapear
1.1 Agrupación usando groupingBy
Agrupar por departamento
Map<String, List<User>> collect = users.stream().collect(
Collectors.groupingBy(
User::getDept
)
);
Agrupar por clave personalizada
Map<String, List<User>> groupByDeptAppendName = users.stream().collect(
Collectors.groupingBy(
user -> user.getDept() + "&" + user.getName()
)
);
agrupación multinivel
Map<String, Map<String, List<User>>> groupByDeptAndGender = users.stream()
.filter(user -> Objects.nonNull(user.getSex())) // group by 的字段不能有null值
.collect(
Collectors.groupingBy(
User::getDept,
Collectors.groupingBy(User::getSex)
)
);
Agrupe por departamento y encuentre la lista de ID
Map<String, List<String>> collect = users.stream().collect(
Collectors.groupingBy(
User::getDept,
Collectors.mapping(
User::getId,
Collectors.toList()
)
)
);
{
Java组=[1, 2], QA组=[5], 前端组=[3, 4], 产品组=[6]}
Agrupar por departamento, Contar el número de personas
Map<String, Long> groupBuyDeptThenCount = users.stream().collect(
Collectors.groupingBy(
User::getDept,
Collectors.counting()
)
);
Según agrupación de departamentos, encuentre el Conjunto de Sexo
Map<String, Set<String>> collect = users.stream().collect(
Collectors.groupingBy(
User::getDept,
Collectors.mapping(
User::getSex,
Collectors.toSet()
)
)
);
{
Java组=[女, 男], QA组=[女], 前端组=[男], 产品组=[女]}
Según la agrupación de departamentos, encuentre el número de duplicados en Sexo
Collectors.collectingAndThen()
Acepta dos parámetros: downstream
y finisher
. en
downstream
Es un recopilador que se utiliza para recopilar elementos en el flujo de datos;finisher
Es una función de función que se utiliza paradownstream
procesar los resultados de la recopilación y devolver los resultados finales.
Map<String, Integer> collect = users.stream().collect(
Collectors.groupingBy(
User::getDept,
Collectors.collectingAndThen(
Collectors.mapping(
User::getSex,
Collectors.toSet()
),
a -> a.size()
)
)
);
{
Java组=2, QA组=1, 前端组=1, 产品组=1}
1.2 Usar particionamientoPor particionamiento
Map<Boolean, List<User>> collect = users.stream().collect(
Collectors.partitioningBy(
a -> a.getAge() > 30
)
);
1.3 Usando toMap
Lista 转 Mapa<ID, Usuario>
Map<String, User> userMap = users.stream().collect(
Collectors.toMap(
User::getId,
Function.identity(),
(k1, k2) -> k1 //key重复,用第一个
)
);
Lista 转 Mapa<ID, Nombre>
Map<String, String> idToName = users.stream().collect(
Collectors.toMap(
User::getId,
User::getName
)
);
2 Encuentra el máximo, mínimo, promedio y suma
2.1 Sin agrupación, estadísticas directas
求年龄最大的人:
Optional<User> maxAgeUserOptional = users.stream().collect(
Collectors.maxBy(Comparator.comparing(User::getAge))
);
求年龄最小的人:
Optional<User> minAgeUserOptional = users.stream().collect(
Collectors.minBy(Comparator.comparing(User::getAge))
);
求最大的年龄:
int maxAge = users.stream().mapToInt(User::getAge).max().getAsInt();
求最小的年龄:
int minAge = users.stream().mapToInt(User::getAge).min().getAsInt();
求年龄总和:
int sumAge = users.stream().mapToInt(User::getAge).sum();
求平均年龄:
double avgAge = users.stream().mapToInt(User::getAge).average().getAsDouble();
2.2 Agrupar primero, luego contar
Encuentra la persona con mayor edad en cada departamento
Map<String, User> groupByDeptThenGetMaxAgeUser = users.stream().collect(
Collectors.groupingBy(
User::getDept,
Collectors.collectingAndThen(
Collectors.maxBy(
Comparator.comparing(
User::getAge,
Comparator.nullsLast(Integer::compareTo)
)
),
Optional::get
)
)
);
Encuentre el valor máximo de Edad en cada departamento.
Map<String, Integer> collect = users.stream().collect(
Collectors.groupingBy(
User::getDept,
Collectors.collectingAndThen(
Collectors.maxBy(
Comparator.comparingInt(User::getAge)
),
a -> a.isPresent() ? a.get().getAge() : null
)
)
);
Encuentre la edad promedio en cada departamento.
Map<String, Double> collect = users.stream().collect(
Collectors.groupingBy(
User::getDept,
Collectors.averagingInt(User::getAge)
)
);
Encuentra la suma de Edades en cada departamento.
Map<String, Integer> collect = users.stream().collect(
Collectors.groupingBy(
User::getDept,
Collectors.summingInt(User::getAge)
)
);
Estadísticas usando IntSummaryStatistics
Map<String, IntSummaryStatistics> collect = users.stream().collect(
Collectors.groupingBy(
User::getDept,
Collectors.summarizingInt(
User::getAge
)
)
);
for (Map.Entry<String, IntSummaryStatistics> entry : collect.entrySet()) {
IntSummaryStatistics summaryStatistics = entry.getValue();
System.out.println("----------------key----------------" + entry.getKey());
System.out.println("求和:" + summaryStatistics.getSum());
System.out.println("求平均" + summaryStatistics.getAverage());
System.out.println("求最大:" + summaryStatistics.getMax());
System.out.println("求最小:" + summaryStatistics.getMin());
System.out.println("求总数:" + summaryStatistics.getCount());
}
3 procesamiento de tipo BigDecimal
3.1 Sin agrupación, estadísticas directas
List<BigDecimal> userSalary = users.stream().map(User::getSalary).collect(Collectors.toList());
Optional<BigDecimal> maxSalary = userSalary.stream().reduce(BigDecimal::max);
Optional<BigDecimal> minSalary = userSalary.stream().reduce(BigDecimal::min);
BigDecimal sumSalary = userSalary.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal avgSalary= sumSalary.divide(BigDecimal.valueOf(userSalary.size()), 2, BigDecimal.ROUND_HALF_UP);
3.2 Agrupar primero, luego contar
Buscando el mayor salario de cada departamento
Map<String, BigDecimal> groupByDeptThenGetMaxSalary = users.stream().collect(
Collectors.groupingBy(
User::getDept,
Collectors.reducing(
BigDecimal.ZERO,
User::getSalary,
BigDecimal::max
)
)
);
Buscando el salario más pequeño de cada departamento
Map<String, BigDecimal> groupByDeptThenGetMinSalary = users.stream().collect(
Collectors.groupingBy(
User::getDept,
Collectors.reducing(
BigDecimal.valueOf(Long.MAX_VALUE),
User::getSalary,
BigDecimal::min
)
)
);
如果考虑Salary有null值,可以如下处理
Map<String, BigDecimal> groupByDeptThenGetMinSalary = users.stream().collect(
Collectors.groupingBy(
User::getDept,
Collectors.collectingAndThen(
Collectors.reducing(
(c1, c2) -> c1.getSalary().compareTo(c2.getSalary()) > 0 ? c2 : c1
),
a -> a.isPresent() ? a.get().getSalary() : null
)
)
);
Encuentre el salario total de cada departamento.
Map<String, BigDecimal> groupByDeptThenGetSumSalary = users.stream()
.filter(user -> Objects.nonNull(user.getDept())) //比较的字段不能有null值
.collect(
Collectors.groupingBy(
User::getDept,
Collectors.reducing(
BigDecimal.ZERO,
User::getSalary,
BigDecimal::add
)
)
);
Encuentre el salario promedio para cada departamento.
Collectors
Hay averagingInt、averagingLong、averagingDouble
espera, pero no averagingBigDecimal
.
Consulte java lambada para agrupar y resumir la lista para implementar un promedio personalizadoBigDecimal
Map<String, BigDecimal> groupByDeptThenGetAvgSalary = users.stream()
.filter(user -> Objects.nonNull(user.getDept())) //比较的字段不能有null值
.collect(
Collectors.groupingBy(
User::getDept,
CustomCollectors.averagingBigDecimal(User::getSalary, 2, 2)
)
);