Java8 Stream (12) Collectors.groupingBy Explicación detallada de las estadísticas de agrupación


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: downstreamy finisher. en

  • downstreamEs un recopilador que se utiliza para recopilar elementos en el flujo de datos;
  • finisherEs una función de función que se utiliza para downstreamprocesar 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
                )
        )
);

如果考虑Salarynull值,可以如下处理
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.

CollectorsHay averagingInt、averagingLong、averagingDoubleespera, 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)
                )
        );

Supongo que te gusta

Origin blog.csdn.net/winterking3/article/details/131671534
Recomendado
Clasificación