groupingBy:分组
按条件分组,分组后,返回的是一个Map集合,其中key作为分组条件,value作为对应分组结果
Collectors.groupingBy(…):普通分组。
Collectors.groupingByConcurrent(…):线程安全的分组。
groupingBy(按什么字段分组,可以去Collectors找相关的方法)
一、简单分组范例
// 按年纪分组
Map<Integer, List<Student>> collect1 = list.stream()
.collect(Collectors.groupingBy(Student::getAge));
//velue转换为set集合
Map<Integer, Set<Student>> collect2 = list.stream()
.collect(Collectors.groupingBy(Student::getAge,Collectors.toSet()));
//按性别分组并统计人数
Map<String,Long> map1=list.stream()
.collect(Collectors.groupingBy(Student::getSex,Collectors.counting()));
//按性别分组,求年纪之和
Map<String, Integer> collect = list.stream()
.collect(Collectors.groupingBy(Student::getSex, Collectors.summingInt(Student::getAge)));
//按性别分组,并统计名字作为值
Map<String, List<String>> collect1 = list.stream().collect(Collectors
.groupingBy(Student::getSex, Collectors.mapping(Student::getName, Collectors.toList())));
//聚合数据count,min,max,sum和average
Map<String, DoubleSummaryStatistics> map2 =list.stream().collect(Collectors
.groupingBy(Student::getSex,Collectors.summarizingDouble(Student::getScore)));
System.out.println("所有男的总学分:" + map2.get('男').getSum());
System.out.println("男生最高学分:" + map2.get('男').getMax());
System.out.println("男生最低学分:" + map2.get('男').getMin());
System.out.println("男生的平均分:" + map2.get('男').getAverage());
System.out.println("男生的个数:" + map2.get('男').getCount());
// 类似于SQL中的group by
// 根据工作状态分组 (单级分组) { BUSY: List<User>, FREE: List<User> }
Map<User.Status, List<User>> userMapByStatus = list.stream()
.collect(Collectors.groupingBy(User::getStatus));
// 先根据工作状态分组,再根据年龄分组 (多级分组)
// { BUSY: {21 : List<User>, 23 : List<User>}, FREE : { 25 : List<User>, 26 : List<User> } }
Map<User.Status, Map<Integer, List<User>>> userMapByStatusAndAge = list.stream()
.collect(Collectors.groupingBy(User::getStatus, Collectors.groupingBy(User::getAge)));
// 更多级分组
Map<User.Status, Map<Integer, Map<Double, List<User>>>> userMapByStatusAndAgeAndSalary =
list.stream().collect(Collectors.groupingBy(User::getStatus,
Collectors.groupingBy(User::getAge, Collectors.groupingBy(User::getSalary))));
// 自定义分组,先按工作状态分组,再自定义下一次分组key,比如小于30岁,key为青年,大于30岁,key为中年
// ==> { BUSY : { "青年" : List<User>, "老年" : List<User> } }
list.stream().collect(Collectors.groupingBy(User::getStatus, Collectors.groupingBy(u ->
{ User user = (User)u;
if (user.getAge() < 30) {
return "青年";} else {return "中年";}
} )));
根据单个条件找出重复数据
List<String> prodCdRepeat = prodVoList.stream()
.filter(f -> StringUtils.isNotEmpty(f.getProdCdDis())).map(ImportProdVo::getProdCdDis)
.collect(Collectors.groupingBy(Function.identity()))
.values().stream().filter(list -> list.size() > 1)
.flatMap(Collection::stream).collect(Collectors.toList());
根据多个条件找出重复数据
List<ImportProdVo> prodVoRepeat = prodVoList.stream().collect(Collectors.groupingBy(p -> p.getProdNm() + p.getSpec()+ p.getModel() + p.getBrand())).values().stream().filter(list -> list.size() > 1)
.flatMap(Collection::stream).collect(Collectors.toList());
根据某个字段进行分组
List<TManufOrdEx> batchNoManufOrdList = tManufOrds.stream()
.collect(Collectors.collectingAndThen(Collectors
.toCollection(()-> new TreeSet<>(Comparator.comparing(TManufOrdEx :: getBatchNo))),ArrayList::new));
// 根据某字段进行分组后求和List<TManufOrdEx> sumKgsList = tManufOrdExList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(o - >o.getSellConLineNo()))),ArrayList::new));//筛选过后的订单总数求和
tManufOrdEx.setSumKgs(BigDecimal.valueOf(sumKgsList
.stream().mapToDouble(e->e.getKgs().doubleValue())
.reduce(0,Double::sum)));
根据某几个字段进行分组
List<TManufOrdEx> batchNoManufOrdList = tManufOrds.stream()
.collect(Collectors.collectingAndThen(Collectors
.toCollection(()-> new TreeSet<>(Comparator
.comparing(e -> e.getDaySort() + ";" + e.getEnterVatOrdDt() + ";"
+ e.getMachineId() + ";"))),ArrayList::new));// 或
ArrayList<Student> collect8 = list.stream().collect(Collectors.collectingAndThen(
Collectors.toCollection(() -> new TreeSet<>(
Comparator.comparing(Student::getName)
.thenComparing(Student::getAge))), ArrayList::new));
分区partitioningBy(…)
分区是分组的特殊情况
该方法实质是在做二分组,将符合条件、不符合条件的元素分组到两个key分别为true和false的Map中,从而我们能够得到符合和不符合的分组新集合。
//人名按照中、英文名进行分区
Map<Boolean, List<Student>> collect3 = list.stream().collect(Collectors.partitioningBy(e -> e.getName().matches("^[a-zA-Z]*")));
//取英文集合
List<Student> students = collect3.get(true);
//取中文集合
List<Student> students1 = collect3.get(false);
// 特殊情况下的分组形式,分组条件结果为true/false,即 { true : List<xx>, false : List<xx> }
// 9. 将工资大于6000的分一个区,小于等的分一个区 ==> {true : List<工资大于6000的User>, false : List<工资小于等于6000的User> }
Map<Boolean, List<User>> partitionSalaryMap = list.stream()
.collect(Collectors.partitioningBy(u -> u.getSalary() > 6000));