- Java List中的數據如何根據對象的某一個或多個字段排序引出Comparable和comparator的使用
-
第一節 對於引入題目的探討
首先把引入題目表述的清楚一些,在一個List中存儲的是一些對象實例,而對象實例包含多個屬性字段,我們要根據對象的某個或者多個屬性來對List進行排序。
假設List中存儲的都是Student類的實例,Student類包含name、gender、id屬性。首先根據Student實例中的name屬性排序,如果兩個名字相同,就再根據id屬性排序。
Student類源碼如下:
[java]<strong>package chapter1;
public class Student {
private String name;
private String gender;
private int id;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}</strong>
假設有三個學生:姓名 性別 ID
宋超 男 100120
伍星 男 100121
宋超 女 100122
把這三個學生存儲在List裏面,要求首先按照姓名進行排序,如果姓名相同就按照ID排序。
1.1.1第一種實現方式:使用Comparable接口;
使用這種方式時,Student類必須繼承這個接口,並且實現compareTo方法。並且compareTo方法是這個接口的唯一方法。需要注意到一點,在《Effective Java》第十二條中,提供了一個通用的寫法,也就是在類繼承的Comparable接口的時候,利用泛型指明能比較的類型。把Student類改寫如下:
[java]
package chapter1;
public classStudent implementsComparable<Student>{
private String name;
private String gender;
private int id;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(Stringgender) {
this.gender = gender;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public int compareTo(Student arg0){
//String、Integer、Double、Float等類型都實現有compareTo方法
if(this.name.compareTo(arg0.name) == 0) {
return Integer.valueOf(id).compareTo(Integer.valueOf(arg0.id));
}else{
return this.name.compareTo(arg0.name);
}
}
}
在《Effective Java》中對於compareTo方法有以下幾點提示:
·自反性
·傳遞性
·對稱性
·最好和equals方法值相同
那麼,在客戶端調用的時候,直接寫如下代碼:[java]
package chapter1;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class ClientInterface {
publicstatic void main(String[] args) {
Studentsongchao = new Student();
songchao.setGender("Man");
songchao.setId(100150);
songchao.setName("SongChao");
Studentwuxing = new Student();
wuxing.setGender("Man");
wuxing.setId(100121);
wuxing.setName("WuXing");
Studentsongchao2 = new Student();
songchao2.setGender("Women");
songchao2.setId(100130);
songchao2.setName("SongChao");
List<Student>students = new ArrayList<Student>();
students.add(songchao);
students.add(wuxing);
students.add(songchao2);
for(Studentstudent : students) {
System.out.println("Name " + student.getName() + " ID " + student.getId());
}
System.out.println();
Collections.sort(students);
for(Studentstudent : students) {
System.out.println("Name " + student.getName() + " ID " + student.getId());
}
}
}
輸出結果如下:[java]
Name SongChao ID 100150
Name WuXing ID 100121
Name SongChao ID 100130
Name SongChao ID 100130
Name SongChao ID 100150
Name WuXing ID 100121
1.1.2另外一種方式:直接使用比較器comparator
直接使用比較器的情況下,Student類不必繼承Comparable接口,當然也不必實現compareTo方法。
直接看調用代碼,但是注意一點,這裏的Student類沒有繼承Comparable接口。
直接在上面的客戶端代碼中,把Collections.sort方法替換爲:[java]
Collections.sort(students, newComparator<Student>() {
@Override
public int compare(Student arg0,Student arg1) {
if(arg0.getName().compareTo(arg1.getName())== 0) {
return Integer.valueOf(arg0.getId()).compareTo(Integer.valueOf(arg1.getId()));
} else {
returnarg0.getName().compareTo(arg1.getName());
}
}
});
輸出結果和第一種方式相同。
還有一個注意點,那就是排序的順序,是按照由小到大還是由大到小。上面那種方式顯然是從小到大排序,那麼如何從大到小排序?只要改變參數順序即可:
[java]
Collections.sort(students,newComparator<Student>() {
@Override
public int compare(Student arg0,Student arg1) {
if(arg1.getName().compareTo(arg0.getName()) == 0) {
return Integer.valueOf(arg1.getId()).compareTo(Integer.valueOf(arg0.getId()));
}else{
return arg1.getName().compareTo(arg0.getName());
}
}
});
以上是對於sort方法的小總結,Arrays中的sort方法類似。
第二節 Collections與Arrays概念分析
1.2.1 Collection和Collections的區別
Collection是java.util下的接口,是各種集合結構的父接口。繼承它的接口主要有Set和List。
Collections是java.util下的專用靜態類,包含有各種有關集合操作的靜態方法。提供一系列靜態方法實現對各種集合的搜索、排序、線程安全化等操作。
1.2.2 Array與Arrays的區別
Arrays也是一個靜態類,專門用來操作array,提供搜索、排序等靜態方法,還提供一個允許把數組當作列表查看的靜態工廠方法asList。
第三節 其它常用方法總結(第四節爲使用中容易出現錯誤的方法介紹,第五節源代碼)
1.3.1 Collections中的常用方法
java.util.Collections提供了一些靜態方法實現了基於list容器的一些常用算法:
1) addAll(Collection c, T… elements);//將所有指定的元素添加到指定的collection中。
2) void sort(List);//對list容器裏的元素進行排序
3) void reverse(List);//對List容器對象進行逆序排序
4) void copy(Listdest,List src)//將List src容器裏的內容全部拷貝到List dest容器中
5) int binarySearch(List,Object)//對於順序的List容器中採用折半查找的方法查找特定的對象
6) boolean disjoint(Collection c1, Collection c2);//如果兩個指定的collection中沒有相同的元素,返回true。
7) fill(List list, T obj); // 使用指定元素替換指定列表中的所有元素。
8) int frequency(Collection c, Object o);//返回指定的Collection中對於指定對象的元素數。
9) indexOfSubList(List src, List target);//返回源表中第一次出現指定目標列表的起始位置,如果沒有這樣的列表就返回-1。
10) lastIndexOfSubList(List src, List target);//最後一次的起始位置,沒有則返回-1
11) max(Collection coll);//根據元素的自然順序,返回collection的最大值;
12) max(Collection coll,Comparator comp);//根據比較器產生的順序,返回最大元素。
13) min同上
14) replaceAll(List list, T oldVal, T newVal);//使用另外一個值替換列表中出現的所有某一指定值。
15) reverseOrder();//逆轉comparable接口的對象collection的自然順序。例如:假設a是一個字符串數組,那麼:
Arrays.sort(a, Collections.reverseOrder());將會按照字典逆序排序。
16) reverseOrder(Comparator cmp);返回一個強行逆轉比較器的順序
17) rotate(List list, intdistance);//根據指定的距離輪換列表中的元素。
18) shuffle(List list);//對列表隨機排序
19) shuffle(List list, Random rnd);//根據指定的隨機源排序
20) swap(List list, int i, int j);//在指定列表的指定位置處交換元素
[java]
package chapter1;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
public class CollectionsMethod {
/**
* @param args
*/
public static void main(String[] args) {
List<Integer> collection = new ArrayList<Integer>();
/*1----兩種方式 */
Collections.addAll(collection, 1, 2, 3);
System.out.println(collection.toString());
Integer[] moreInts = {10, 7, 4, 9};
Collections.addAll(collection, moreInts);
System.out.println(collection.toString());
/*2----簡單類型下sort的使用 */
Collections.sort(collection);
System.out.println(collection.toString());
/*3----逆序*/
Collections.reverse(collection);
System.out.println(collection.toString());
/*4----複製*/
List<Integer> copyList = new ArrayList(Arrays.asList( new Object[collection.size()]));
Collections.copy(copyList, collection);
copyList.remove(0);
System.out.println(copyList.size());
System.out.println(copyList.toString());
System.out.println(collection.toString());
/*4----另外一種方式 */
List array = new ArrayList(collection);
System.out.println(array.toString());
System.out.println(collection.toString());
/*5----二分查找,首先把列表排序才行 */
List<Integer> bsList = new ArrayList<Integer>();
bsList.add(9);
bsList.add(12);
bsList.add(2);
bsList.add(78);
bsList.add(10);
System.out.println(bsList.toString());
Collections.sort(bsList);
System.out.println(bsList);
int index = Collections.binarySearch(bsList, 20);
System.out.println(index);
/*6----判定兩個collection中是否沒有相同的元素,返回布爾值*/
System.out.println(Collections.disjoint(bsList, array));
/*7----返回指定對象的個數*/
System.out.println(Collections.frequency(bsList, 10));
/*8----子列表在指定列表中的位置*/
List<Integer> subList = new ArrayList<Integer>();
subList.add(9);
subList.add(10);
subList.add(5);
subList.add(1);
System.out.println(Collections.indexOfSubList(bsList, subList));
/*9----返回最大最小值 & 倒序 & 循環移位 & 交換*/
System.out.println(Collections.max(subList));
Collections.reverseOrder();
System.out.println(subList.toString());
Collections.rotate(subList, 2);
System.out.println(subList.toString());
Collections.swap(subList, 0, 2);
System.out.println(subList.toString());
}
}
1.3.2 Arrays中的常用方法
Arrays中的方法比較簡單,基本上分爲
1) asList方法,把一個數組轉換成list
2) 二分查找方法,可以指定在數組中的範圍內執行
3) toString方法
4) sort方法
第四節 容易出現錯誤的方法介紹
1.4.1Collections中容易出現錯誤的方法介紹
1)copy方法
所以使用了Collections.copy()方法來進行拷貝,但是這樣就接觸到了此方法所報出的異常:
舉例如下:
List src1 = new ArrayList( 3 )
src1.add( " a " );
src2.add( " b " );
src3.add( " c " );如果你使用下面方法copy鏈表
/** **************************** */
List des1 = new ArrayList( 3 );www.2cto.com
Collections.copy(des1,src1);
/** **************************** */
將會出錯,拋出數組越界異常。明明已經設置了長度爲3,爲什麼還會出錯?
打印出des1.size()才知道des1的長度爲0;3表示的是這個List的容納能力爲3,並不是說des1中就有了3個元素。查看api才知 道,它的capacity(容納能力大小)可以指定(最好指定)。而初始化時size的大小永遠默認爲0,只有在進行add和remove等相關操作 時,size的大小才變化。然而進行copy()時候,首先做的是將desc1的size和src1的size大小進行比較,只有當desc1的 size 大於或者等於src1的size時才進行拷貝,否則拋出IndexOutOfBoundsException異常。
作者:Allen_Zhao_2012
package com.compare.test; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class Main { public static void main(String[] args) { Main mainTest=new Main(); mainTest.sortMap(); } public void sortMap(){ List<Map<Integer, Double>> maps=new ArrayList<Map<Integer, Double>>(); for(int i=0;i<10;i++){ HashMap<Integer, Double> map=new HashMap<Integer, Double>(); for(int j=0;j<2;j++){ map.put(j, Math.random()); } maps.add(map); } for(Map<Integer, Double> map:maps){ System.out.println(getValue(map)); } System.out.println("************************"); Map<Integer, Double> currentMap; for(int i=0;i<maps.size()-1;i++){ for(int j=0;j<maps.size()-i-1;j++){ if(getValue(maps.get(j))>getValue(maps.get(j+1))){ currentMap=maps.get(j+1); maps.set(j+1, maps.get(j)); maps.set(j,currentMap); } } } for(Map<Integer, Double> map:maps){ System.out.println(getValue(map)); } } public Double getValue(Map<Integer, Double> currentMap){ return currentMap.get(0)+currentMap.get(1); } }
我採用最簡單的排序大數沉底。而且getValue
方法你可以自己實現,決定使用哪幾個進行排序。(我們有進行key值不存在的判斷)
Java 對象多字段排序 Comparator
Java 反射類:ReflexUtil
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
|
public class
ReflexUtil { static Logger
logger = LoggerFactory.getLogger(ReflexUtil. class ); //getMethod static public
Object invokeMethod(String propertiesName, Object object) { try { if (object== null ) return null ; if (!propertiesName.contains( "." ))
{ String
methodName = "get" +getMethodName(propertiesName); Method
method = object.getClass().getMethod(methodName); return method.invoke(object); } String
methodName = "get" +getMethodName(propertiesName.substring( 0 ,propertiesName.indexOf( "." ))); Method
method = object.getClass().getMethod(methodName); return invokeMethod(propertiesName.substring(propertiesName.indexOf( "." )+ 1 ),
method.invoke(object)); } catch (Exception
e) { logger.error(e.toString(),
e); return null ; } } private static
String getMethodName(String fildeName) { byte []
items = fildeName.getBytes(); items[ 0 ]
= ( byte )
(( char )
items[ 0 ]
- 'a' +
'A' ); return new
String(items); } public static
void
main(String args[]) { Video
video = new Video(); Album
album = new Album(); album.setAlbumId(346l); video.setAlbum(album); video.setVideoId(126l); System.out.println(ReflexUtil.invokeMethod( "album.albumId" ,
video)); } } |
Java 對象排序 : CompareUtil
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
|
public class
CompareUtil { //sort
1正序 -1 倒序 filed 多字段排序 public static
<t> Comparator createComparator( int sort,
String... filed) { return new
ImComparator(sort, filed); } public static
class
ImComparator implements Comparator
{ int sort
= 1 ; String[]
filed; public ImComparator( int sort,
String... filed) { this .sort
= sort == - 1 ?
- 1 :
1 ; this .filed
= filed; } @Override public int
compare(Object o1, Object o2) { int result
= 0 ; for (String
file : filed) { Object
value1 = ReflexUtil.invokeMethod(file, o1); Object
value2 = ReflexUtil.invokeMethod(file, o2); if (value1
== null ||
value2 == null )
{ continue ; } if (!(value1
instanceof Integer)
|| !(value1 instanceof Integer))
{ continue ; } int v1
= Integer.valueOf(value1.toString()); int v2
= Integer.valueOf(value2.toString()); if (v1
== v2) continue ; if (sort
== 1 )
{ return v1
- v2; } else if
(sort == - 1 )
{ return v2
- v1; } else { continue ; } } return result; } } public static
void
main(String args[]) { LabelAlbum
label1 = new LabelAlbum(); label1.setLabelId( 1 );
label1.setSequnces( 1 ); LabelAlbum
label2 = new LabelAlbum(); label2.setLabelId( 1 );label2.setSequnces( 2 ); LabelAlbum
label3 = new LabelAlbum(); label3.setLabelId( 3 );
label3.setSequnces( 4 ); LabelAlbum
label4 = new LabelAlbum(); label4.setLabelId( 3 );label4.setSequnces( 3 ); LabelAlbum
label5 = new LabelAlbum(); label5.setLabelId( 4 );label5.setSequnces( 2 ); List<labelalbum>
list = new ArrayList<labelalbum>(); list.add(label1); list.add(label2); list.add(label3); list.add(label4); list.add(label5); Collections.sort(list,
CompareUtil.createComparator( 1 , "labelId" , "sequnces" )); for ( int i
= 0 ;
i < list.size(); i++) { LabelAlbum
labelAlbum=list.get(i); System.out.println( "labelId:" +labelAlbum.getLabelId()+ "
sequence:" +labelAlbum.getSequnces()); } } }</labelalbum></labelalbum></t> |
mathmatic使用說明