提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
之前记录过:stream的三个常用方式(toMap,groupingBy,findFirst)。
这里继续记录下groupingBy的几个高级用法。
个人认为,最有分歧的是:实现分组,且每个分组也进行排序
这里要特别说明
下:
从方法上看,分组之后,是不能对每个分组进行比较的(也就无法排序)
Collectors.groupingBy(Function<? super T, ? extends K> classifier,
Collector<? super T, A, D> downstream)
这里有两个思路:
1:提前排序,再进行分组
2:分组后,对Map进行处理,对其每个value排序
这主要列举了常用的:summingInt、counting、mapping、分组生序排序,分组降序排序
一、groupingBy高级用法
import com.alibaba.fastjson.JSONObject;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class Test {
public static void main(String[] args) {
Student student1 = new Student(1, 1);
Student student2 = new Student(1, 1);
Student student3 = new Student(2, 2);
Student student4 = new Student(2, 3);
Student student5 = new Student(3, 3);
Student student6 = new Student(3, 4);
Student student7 = new Student(4, 1);
Student student8 = new Student(4, 1);
Student student9 = new Student(4, 2);
Student student10 = new Student(4, 1);
List<Student> list = Arrays.asList(student1, student2, student3, student4, student5, student6, student7, student8, student9, student10);
System.out.println("--------- 根据字段分组,求每个分组的sum ----------");
Map<Integer, Integer> collect = list.stream().collect(Collectors.groupingBy(Student::getId, Collectors.summingInt(Student::getScore)));
System.out.println(collect.toString());
System.out.println("--------- 根据字段分组,求每个分组的count ----------");
Map<Integer, Long> countMap = list.stream().collect(Collectors.groupingBy(Student::getId, Collectors.counting()));
System.out.println(countMap.toString());
System.out.println("--------- 根据字段分组,每个分组为:对象的指定字段 ----------");
Map<Integer, List<Integer>> groupMap = list.stream().collect(Collectors.groupingBy(Student::getId, Collectors.mapping(Student::getScore, Collectors.toCollection(ArrayList::new))));
System.out.println(groupMap.toString());
System.out.println("--------- 根据字段分组,默认分组 ----------");
Map<Integer, List<Student>> defaultGroupMap = list.stream().collect(Collectors.groupingBy(Student::getId));
System.out.println(JSONObject.toJSONString(defaultGroupMap));
System.out.println("--------- 根据字段分组,每个分组按照指定字段进行生序排序 ----------");
Map<Integer, List<Student>> sortGroupMap = list.stream().sorted(Comparator.comparing(Student::getScore))
.collect(Collectors.groupingBy(Student::getId));
System.out.println(JSONObject.toJSONString(sortGroupMap));
System.out.println("--------- 先排序,再分组 ----------");
Map<Integer, List<Student>> reversedSortGroupMap = list.stream().sorted(Comparator.comparing(Student::getScore).reversed())
.collect(Collectors.groupingBy(Student::getId));
System.out.println(JSONObject.toJSONString(reversedSortGroupMap));
}
}
class Student {
private Integer id;
private Integer score;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getScore() {
return score;
}
public void setScore(Integer score) {
this.score = score;
}
public Student(Integer id, Integer score) {
this.id = id;
this.score = score;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
执行结果
--------- 根据字段分组,求每个分组的sum ----------
{1=2, 2=5, 3=7, 4=5}
--------- 根据字段分组,求每个分组的count ----------
{1=2, 2=2, 3=2, 4=4}
--------- 根据字段分组,每个分组为:对象的指定字段 ----------
{1=[1, 1], 2=[2, 3], 3=[3, 4], 4=[1, 1, 2, 1]}
--------- 根据字段分组,默认分组 ----------
{1:[{"id":1,"score":1},{"id":1,"score":1}],2:[{"id":2,"score":2},{"id":2,"score":3}],3:[{"id":3,"score":3},{"id":3,"score":4}],4:[{"id":4,"score":1},{"id":4,"score":1},{"id":4,"score":2},{"id":4,"score":1}]}
--------- 根据字段分组,每个分组按照指定字段进行生序排序 ----------
{1:[{"id":1,"score":1},{"id":1,"score":1}],2:[{"id":2,"score":2},{"id":2,"score":3}],3:[{"id":3,"score":3},{"id":3,"score":4}],4:[{"id":4,"score":1},{"id":4,"score":1},{"id":4,"score":1},{"id":4,"score":2}]}
--------- 先排序,再分组 ----------
{1:[{"id":1,"score":1},{"id":1,"score":1}],2:[{"id":2,"score":3},{"id":2,"score":2}],3:[{"id":3,"score":4},{"id":3,"score":3}],4:[{"id":4,"score":2},{"id":4,"score":1},{"id":4,"score":1},{"id":4,"score":1}]}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
二、先分组,再排序
先将数据进行groupingBy,得到Map<Long, List>。
在通过forEach对每个List进行排序
Map<Long, List<StreamMapEntity>> map = getMap();
System.out.println("------ flatMap 处理Map<Long,List<StreamMapEntity>> ------");
System.out.println();
System.out.println("初始数据:" + JSONObject.toJSONString(map));
System.out.println();
map.keySet().forEach(key -> map.computeIfPresent(key, (k, v) -> v.stream().sorted(Comparator.comparing(StreamMapEntity::getId).reversed()).collect(Collectors.toList())));
System.out.println("处理map:对map内的每个list进行排序:");
System.out.println(JSONObject.toJSONString(map));
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
执行结果:
------ flatMap 处理Map<Long,List<StreamMapEntity>> ------
初始数据:{1111:[{"id":1,"name":"aa"},{"id":2,"name":"bb"},{"id":3,"name":"cc"},{"id":4,"name":"dd"}],2222:[{"id":5,"name":"ee"},{"id":6,"name":"ff"},{"id":7,"name":"gg"},{"id":8,"name":"hh"}]}
处理map:对map内的每个list进行排序:
{1111:[{"id":4,"name":"dd"},{"id":3,"name":"cc"},{"id":2,"name":"bb"},{"id":1,"name":"aa"}],2222:[{"id":8,"name":"hh"},{"id":7,"name":"gg"},{"id":6,"name":"ff"},{"id":5,"name":"ee"}]}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
总结
关于分组排序的两种方式:先排序再分组;先分组再排序。
效率上肯定是先排序再分组快。
- Collectors groupingBy Streamcollectors groupingby stream list collectors groupingby顺序 collectors groupingby lambda java collectors groupingby条件 百分比 百分collectors groupingby 字段collectors groupingby java collectors stream java util groupingby stream java8 java collectors 20230619 stream java collectingandthen collectors方法stream