失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > Java8 Stream(12)Collectors.groupingBy 分组统计详解

Java8 Stream(12)Collectors.groupingBy 分组统计详解

时间:2024-04-11 11:55:24

相关推荐

Java8 Stream(12)Collectors.groupingBy 分组统计详解

Collectors.groupingBy 分组统计详解

1 List 转 Map1.1 使用 groupingBy 分组根据部门分组按照自定义Key分组多级分组根据部门分组,求ID的List根据部门分组,Count人数根据部门分组,求Sex的Set根据部门分组,求Sex的去重个数 1.2 使用 partitioningBy 分区1.3 使用 toMapList 转 Map<ID, User>List 转 Map<ID, Name> 2 求最大值、最小值、平均值、总和2.1 不分组,直接统计2.2 先分组,再统计求各个部门中,Age最大的人求各个部门中,Age的最大值求各个部门中,Age的平均值求各个部门中,Age的总和使用 IntSummaryStatistics 统计 3 BigDecimal 类型处理3.1 不分组,直接统计3.2 先分组,再统计求各个部门,最大的Salary求各个部门,最小的Salary求各个部门,Salary总和求各个部门,Salary平均值

工作中能够熟练使用Collectors中groupingBy、reducing、toMap非常重要,因为这些巧妙的函数可以大大提高开发效率,所以学习好它们刻不容缓。先准备好一个List集合供测试用。

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 List 转 Map

1.1 使用 groupingBy 分组

根据部门分组

Map<String, List<User>> collect = users.stream().collect(Collectors.groupingBy(User::getDept));

按照自定义Key分组

Map<String, List<User>> groupByDeptAppendName = users.stream().collect(Collectors.groupingBy(user -> user.getDept() + "&" + user.getName()));

多级分组

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)));

根据部门分组,求ID的List

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]}

根据部门分组,Count人数

Map<String, Long> groupBuyDeptThenCount = users.stream().collect(Collectors.groupingBy(User::getDept,Collectors.counting()));

根据部门分组,求Sex的Set

Map<String, Set<String>> collect = users.stream().collect(Collectors.groupingBy(User::getDept,Collectors.mapping(User::getSex,Collectors.toSet())));

{Java组=[女, 男], QA组=[女], 前端组=[男], 产品组=[女]}

根据部门分组,求Sex的去重个数

Collectors.collectingAndThen()它接受两个参数:downstreamfinisher。其中

downstream是一个Collector收集器,用于对数据流中的元素进行收集操作;finisher是一个Function函数,用于对downstream的收集结果进行处理,并返回最终的结果。

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 使用 partitioningBy 分区

Map<Boolean, List<User>> collect = users.stream().collect(Collectors.partitioningBy(a -> a.getAge() > 30));

1.3 使用 toMap

List 转 Map<ID, User>

Map<String, User> userMap = users.stream().collect(Collectors.toMap(User::getId,Function.identity(),(k1, k2) -> k1 //key重复,用第一个));

List 转 Map<ID, Name>

Map<String, String> idToName = users.stream().collect(Collectors.toMap(User::getId,User::getName));

2 求最大值、最小值、平均值、总和

2.1 不分组,直接统计

求年龄最大的人:Optional<User> maxAgeUserOptional = users.stream().collect(Collectors.maxBy(paring(User::getAge)));求年龄最小的人:Optional<User> minAgeUserOptional = users.stream().collect(Collectors.minBy(paring(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 先分组,再统计

求各个部门中,Age最大的人

Map<String, User> groupByDeptThenGetMaxAgeUser = users.stream().collect(Collectors.groupingBy(User::getDept,Collectors.collectingAndThen(Collectors.maxBy(paring(User::getAge,Comparator.nullsLast(Integer::compareTo))),Optional::get)));

求各个部门中,Age的最大值

Map<String, Integer> collect = users.stream().collect(Collectors.groupingBy(User::getDept,Collectors.collectingAndThen(Collectors.maxBy(paringInt(User::getAge)),a -> a.isPresent() ? a.get().getAge() : null)));

求各个部门中,Age的平均值

Map<String, Double> collect = users.stream().collect(Collectors.groupingBy(User::getDept,Collectors.averagingInt(User::getAge)));

求各个部门中,Age的总和

Map<String, Integer> collect = users.stream().collect(Collectors.groupingBy(User::getDept,Collectors.summingInt(User::getAge)));

使用 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 BigDecimal 类型处理

3.1 不分组,直接统计

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 先分组,再统计

求各个部门,最大的Salary

Map<String, BigDecimal> groupByDeptThenGetMaxSalary = users.stream().collect(Collectors.groupingBy(User::getDept,Collectors.reducing(BigDecimal.ZERO,User::getSalary,BigDecimal::max)));

求各个部门,最小的Salary

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)));

求各个部门,Salary总和

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)));

求各个部门,Salary平均值

Collectors中有averagingInt、averagingLong、averagingDouble等,但是没有averagingBigDecimal

参考java lambada 对list进行分组汇总,实现自定义averagingBigDecimal

Map<String, BigDecimal> groupByDeptThenGetAvgSalary = users.stream().filter(user -> Objects.nonNull(user.getDept())) //比较的字段不能有null值.collect(Collectors.groupingBy(User::getDept,CustomCollectors.averagingBigDecimal(User::getSalary, 2, 2)));

如果觉得《Java8 Stream(12)Collectors.groupingBy 分组统计详解》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。