在資料庫中我們可以使用 order by
和 group by
輕鬆實現分組和排序的功能,那麼在Java中我們又該如何實現呢?下面我們一起來研究一番
Comparator
與 Comparable
-
Comparable
是一個排序介面,實現了該介面的類,表示該類支援排序功能,重寫compareTo
方法可使程式按照我們的意願對陣列或列表進行排序 -
Comparator
是一個比較器介面,如果我們需要對類進行排序,而該類並沒有實現Comparable
介面,那麼我們可以通過實現Comparator
介面來保持類的排序能力
簡單排序
-
建立一個
Bean
類,我們將對該類進行排序@Data @NoArgsConstructor @AllArgsConstructor public class Student { /** * 班級名稱 */ private String className; /** * 學生姓名 */ private String name; /** * 分數 */ private Integer score; } 複製程式碼
-
準備一些資料,用於測試
final String classOne = "一班"; final String classTwo = "二班"; final String classThree = "三班"; List<Student> students = new ArrayList<>(); students.add(new Student(classOne, "李一", 43)); students.add(new Student(classOne, "王二", 75)); students.add(new Student(classOne, "張三", 91)); students.add(new Student(classTwo, "郭子", 59)); students.add(new Student(classTwo, "潘子", 88)); students.add(new Student(classTwo, "劉子", 97)); students.add(new Student(classThree, "陳六", 66)); students.add(new Student(classThree, "唐七", 77)); students.add(new Student(classThree, "周八", 89)); 複製程式碼
-
建立一個
Comparator
物件如果我們將第一引數與第二個引數進行比較,那麼表示這是一個升序序列(自然排序),否則表示一個降序序列。 當然這樣說並不完全準確,主要還是看返回的整數值是大於零、小於零還是等於零,只有當大於零時物件
o2
才會置於物件o1
前面// 按分數進行降序排序 Comparator<Student> comparator = (o1, o2) -> o2.getScore().compareTo(o1.getScore()); 複製程式碼
-
測試排序結果
Collections.sort(students, comparator); students.forEach(System.out::println); 複製程式碼
列印結果,可以看出列表是按分數進行排序的,接下來我們將對班級名稱進行分組並按分數排序
Student(className=二班, name=劉子, score=97) Student(className=一班, name=張三, score=91) Student(className=三班, name=周八, score=89) Student(className=二班, name=潘子, score=88) Student(className=三班, name=唐七, score=77) Student(className=一班, name=王二, score=75) Student(className=三班, name=陳六, score=66) Student(className=二班, name=郭子, score=59) Student(className=一班, name=李一, score=43) 複製程式碼
分組排序
-
建立一個分組排序的
Comparator
物件由於我們需要按班級名稱進行分組排序,所以我們必須進行兩次計較,第一次比較是否是相同的班級名稱,如果不是直接返回比較的結果值即可,否則返回分數的比較結果
Comparator<Student> groupComparator = (o1, o2) -> { int diff = o1.getClassName().compareTo(o2.getClassName()); return diff == 0 ? o2.getScore().compareTo(o1.getScore()) : diff; }; 複製程式碼
-
測試排序結果
Collections.sort(students, groupComparator); students.forEach(System.out::println); 複製程式碼
列印結果,可以看出確實時按班級分組排序的,但是如果我們想要班級名稱也是按順序排的呢,怎麼做?
Student(className=一班, name=張三, score=91) Student(className=一班, name=王二, score=75) Student(className=一班, name=李一, score=43) Student(className=三班, name=周八, score=89) Student(className=三班, name=唐七, score=77) Student(className=三班, name=陳六, score=66) Student(className=二班, name=劉子, score=97) Student(className=二班, name=潘子, score=88) Student(className=二班, name=郭子, score=59) 複製程式碼
有序的分組排序
如何讓分組的名稱按照我們想要的順序出現?簡單,請看下面
-
定義一個分組順序
分組順序用來判斷該分組所在位置,這樣我們就可以自定義分組的位置,從而實現有序的分組
Map<String, Integer> groupOrder = new HashMap<>(4); groupOrder.put(classOne, 1); groupOrder.put(classTwo, 2); groupOrder.put(classThree, 3); 複製程式碼
-
建立一個有序的分組排序
Comparator
物件通過自定義的班級順序來決定班級名稱出現的位置
Comparator<Student> orderlyGroupComparator = (o1, o2) -> { int diff = groupOrder.get(o1.getClassName()).compareTo(groupOrder.get(o2.getClassName())); return diff == 0 ? o2.getScore().compareTo(o1.getScore()) : diff; }; 複製程式碼
-
測試排序結果
Collections.sort(students, orderlyGroupComparator); students.forEach(System.out::println); 複製程式碼
列印結果
Student(className=一班, name=張三, score=91) Student(className=一班, name=王二, score=75) Student(className=一班, name=李一, score=43) Student(className=二班, name=劉子, score=97) Student(className=二班, name=潘子, score=88) Student(className=二班, name=郭子, score=59) Student(className=三班, name=周八, score=89) Student(className=三班, name=唐七, score=77) Student(className=三班, name=陳六, score=66) 複製程式碼
總結
現在回過去看,原來分組排序如此的簡單呀,不過這完全得益於 Comparator
的強大,你也完全可以選擇實現 Comparable
介面來達到相同的效果。
當有新的挑戰時,我們一定要多思考:facepunch:
由於本人水平有限,有不正確的地方,還望指正,謝謝