標籤:
實際開發中,我們經常需要對一個實體集合中的實體按照實體的某一個欄位進行排序,然後再有序地顯示到介面上。例如:我們得到了一個學生集合,而需求要求我們可以按照學生的姓名排序或學產生績排序。
我們得到的實體集合一般是List或Set類型,所以這裡就對二者的排序進行簡介。
1、List排序
List集合本身是有序的,所以對它的排序較簡單,這雷根據List集合元素的類型分為如下兩類:
1.1 集合元素可自然排序時
所謂的“可自然排序”,指的是List集合中的元素的類型實現了Comparable<T>介面,如,String類型與Integer類型:
此種類型的List排序很簡單,只需要調用Collections.sort(List<T>list)即可對參數中List進行排序,執行個體如下:
public class TestListSort {@SuppressWarnings("unchecked")public static void main(String[] argStrings) {ArrayList strList = new ArrayList();ArrayList intList = new ArrayList();strList.add("b");strList.add("a");strList.add("c");intList.add(2);intList.add(1);intList.add(3);print(intList);// 1.0、排序【前】輸出:2 1 3print(strList);// 1.1、排序【前】輸出:b a cCollections.sort(intList);Collections.sort(strList);print(intList);// 2.0、排序【後】輸出:1 2 3print(strList);// 2.1、排序【後】輸出:a b c}public static void print(List list) {for (int i = 0; i < list.size(); i++) {System.out.println(list.get(i));}}}
1.2 集合元素【不】可自然排序時
即List集合中的元素的類型【沒有】實現Comparable<T>介面,例如為自訂類(Student)。這時需要用Collections.sort(List<T>list, Comparator<? super T> c)進行排序,該方法的核心為第二個參數,即自訂一個定序。執行個體如下:
1、下面我們先自訂一個學生類(Student):
public class Student {private String stuName;private int score;// ------get/setpublic String getStuName() {return stuName;}public void setStuName(String stuName) {this.stuName = stuName;}public int getScore() {return score;}public void setScore(int score) {this.score = score;}}
2、然後構造一個List<Student>類型的對象,以及列印方法
public static List<Student> getListStudents() {List<Student> listStudents = new ArrayList<Student>();Student stu2 = new Student();stu2.setStuName("stu2");stu2.setScore(70);Student stu1 = new Student();stu1.setStuName("stu1");stu1.setScore(50);Student stu3 = new Student();stu3.setStuName("stu3");stu3.setScore(90);listStudents.add(stu2);listStudents.add(stu1);listStudents.add(stu3);return listStudents;}public static void printStuListName(List<Student> list) {for (int i = 0; i < list.size(); i++) {System.out.println(list.get(i).getStuName());}}
3、然後測試按照【姓名】對List<Student>進行排序
public static void main(String[] args) {List<Student> listStudents = getListStudents();printStuListName(listStudents);// 1、排序【前】輸出:stu2 stu1 stu3System.out.println("----------------------------------------");// 自訂定序,按照學生的【姓名】進行排序Collections.sort(listStudents, new Comparator<Student>() {@Overridepublic int compare(Student stu1, Student stu2) {return stu1.getStuName().compareTo(stu2.getStuName());// 按照【姓名】排序// return stu1.getScore() > stu2.getScore() ? 1 : -1;// 按照【年齡】排序}});printStuListName(listStudents);// 2、按照【姓名】排序【後】輸出:stu1 stu2 stu3}
2、TreeSet排序
在實際項目中,實體關聯中有一對多或多對多的關係時,多的一方一般用Set集合(HashSet)表示,所以我們擷取到一個實體集合返回到介面時往往也需要根據Set集合中的某個欄位排序。實體關聯一般用HashSet,但我們知道HashSet本身是無序的,但TreeSet是有序的,所以對HashSet排序的一種思路就是先轉為TreeSet再排序,HashSet排序的幾種思路將在後面介紹。下面介紹TreeSet的排序。
2.1 排序原理
TreeSet的排序其實與上面的List排序原理大同小異,不同的是, TreeSet在放入(add)元素的時候,(如果集合元素可自然排序)就會自動調用排序方法(compareTo())對集合中的元素進行了排序。而不用手動再調用某一個排序方法。執行個體如下:
public class TestTreeSetSort {@SuppressWarnings("unchecked")public static void main(String[] args) {TreeSet treeSet = new TreeSet();// 跟蹤源碼會發現,當執行TreeSet 的add方法時會自動對裡面的元素進行排序treeSet.add("a");treeSet.add("c");treeSet.add("b");Iterator treeSetIterator = treeSet.iterator();// 迴圈輸出treeSet內容:a b cwhile (treeSetIterator.hasNext()) {System.out.println(treeSetIterator.next());}}}
下面對一個Student(同1.2中的Student類)的TreeSet集合的排序進行思路分析,一般有兩種思路:
2.2 使用TreeSet的預設排序,集合元素實現Comparable介面
即運用上面的TreeSet的預設排序原理,將Student對象放入TreeSet集合時自動排序。
當然一成不變的Student類是不能自動排序的,要想享受這一服務,就需要改造這個Student,讓它實現Comparable介面,並重寫compareTo()方法,我們即可在該方法中自訂定序,代碼如下:
2.2.1、改造後的Student類
public class Student implements Comparable {private String stuName;private int score;// 當執行TreeSet<Student>的add()方法時會自動調用該方法進行排序@Overridepublic int compareTo(Object obj) {Student stu = (Student) obj;return this.stuName.compareTo(stu.getStuName());}// ------get/setpublic String getStuName() {return stuName;}public void setStuName(String stuName) {this.stuName = stuName;}public int getScore() {return score;}public void setScore(int score) {this.score = score;}}
2.2.2、然後構造一個TreeSet<Student>類型的對象,以及列印方法
public static TreeSet<Student> getTreeSetStudents() {TreeSet<Student> treeSetStudents = new TreeSet<Student>();Student stu2 = new Student();stu2.setStuName("stu2");stu2.setScore(70);Student stu1 = new Student();stu1.setStuName("stu1");stu1.setScore(50);Student stu3 = new Student();stu3.setStuName("stu3");stu3.setScore(90);// 當執行add方法時會自動調用Student類的compareTo()方法進行排序treeSetStudents.add(stu2);treeSetStudents.add(stu1);treeSetStudents.add(stu3);return treeSetStudents;}public static void printStuTreeSetName(TreeSet<Student> treeSetStudents) {for (Student student : treeSetStudents) {System.out.println(student.getStuName());}}
2.2.3、然後測試輸出構造的TreeSet<Student>對象,看是否已被排序
public static void main(String[] args) {TreeSet<Student> treeSetStudents = getTreeSetStudents();printStuTreeSetName(treeSetStudents);// 輸出已排好序的:stu1 stu2 stu3}
2.3 通過TreeSet(Comparator<? super E>comparator)方法排序
即手動構造TreeSet的比較子進行排序,形式不同,其實原理是一樣的,代碼如下:
2.3.1、還用原始的學生類(Student):
public class Student {private String stuName;private int score;// ------get/setpublic String getStuName() {return stuName;}public void setStuName(String stuName) {this.stuName = stuName;}public int getScore() {return score;}public void setScore(int score) {this.score = score;}}
2.3.2、然後自訂一個排序(比較)類
/** * @author wangzhipeng * */public class MyComparator implements Comparator {@Overridepublic int compare(Object element1, Object element2) {Student stu1 = (Student) element1;Student stu2 = (Student) element2;int result = stu1.getStuName().compareTo(stu2.getStuName());return result;}}
2.3.3、然後構造一個TreeSet<Student>類型的對象【要將上面的MyComparator的一個對象當做參數傳進去】,以及列印方法
public static TreeSet<Student> getTreeSetStudents() {// 關鍵點,new 一個TreeSet<Student>對象時,將我們寫好的自訂排序類的對象當做參數傳進去TreeSet<Student> treeSetStudents = new TreeSet<Student>(new MyComparator());Student stu2 = new Student();stu2.setStuName("stu2");stu2.setScore(70);Student stu1 = new Student();stu1.setStuName("stu1");stu1.setScore(50);Student stu3 = new Student();stu3.setStuName("stu3");stu3.setScore(90);// 當執行add方法時會自動調用MyComparator類的 compare(Object element1, Object// element2)方法進行排序treeSetStudents.add(stu2);treeSetStudents.add(stu1);treeSetStudents.add(stu3);return treeSetStudents;}public static void printStuTreeSetName(TreeSet<Student> treeSetStudents) {for (Student student : treeSetStudents) {System.out.println(student.getStuName());}}
2.3.4、然後測試輸出構造的TreeSet<Student>對象,看是否已被排序
public static void main(String[] args) {TreeSet<Student> treeSetStudents = getTreeSetStudents();printStuTreeSetName(treeSetStudents);// 輸出已排好序的:stu1 stu2 stu3}
3、HashSet排序
上面我也提到了,實體關聯多的一方一般是用無序的HashSet表示,而不是有序地的TreeSet表示。所以我們下面介紹HashSet的排序思路。
思路很簡單,HashSet是無序的,本身肯定不具備排序的功能,所以想要排序就將其轉化為上面介紹的兩種有序的集合List或TreeSet,代碼如下:
3.1、首先獲得一個HashSet<Student>類型的對象
public static HashSet<Student> getHashSetStudents() {HashSet<Student> hashSetStudents = new HashSet<Student>();Student stu2 = new Student();stu2.setStuName("stu2");stu2.setScore(70);Student stu1 = new Student();stu1.setStuName("stu1");stu1.setScore(50);Student stu3 = new Student();stu3.setStuName("stu3");stu3.setScore(90);// 當執行add方法時會自動調用Student類的compareTo()方法進行排序hashSetStudents.add(stu2);hashSetStudents.add(stu1);hashSetStudents.add(stu3);return hashSetStudents;}
3.2、對這個對象進行排序
public static void main(String[] args) {// 獲得一個HashSet<Student>對象HashSet<Student> hashSetStudents = getHashSetStudents();// 1、將上面的對象轉為一個List<Student>對象,並排序List<Student> listStudents = new ArrayList<Student>(hashSetStudents);Collections.sort(listStudents, new Comparator<Student>() {@Overridepublic int compare(Student stu1, Student stu2) {return stu1.getStuName().compareTo(stu2.getStuName());// 按照【姓名】排序}});// 迴圈輸出已排好序的元素:stu1 stu2 stu3for (Student student : listStudents) {System.out.println(student.getStuName());}// 2、將上面的對象轉為一個TreeSet<Student>對象TreeSet<Student> treeSetStudents = new TreeSet<Student>(new MyComparator());for (Student student : hashSetStudents) {treeSetStudents.add(student);}// 迴圈輸出已排好序的元素:stu1 stu2 stu3for (Student student : treeSetStudents) {System.out.println(student.getStuName());}}
4、總結
這幾種集合的排序貌似有很多種方式,其實底層實現都可歸為一種,無論是調用集合預設的排序方法還是自訂排序方式,其實可以說是一個compare(Object o1,Object o2)方法。
java集合排序