set,map,list集合的特點及其排序的方法
特點:
list:儲存: 有序的 可重複的
訪問:可以for迴圈,foreach迴圈,iterator迭代器 迭代。
set:儲存:無序的 不重複的
訪問:可以foreach迴圈,iterator迭代器 迭代
map:儲存:儲存的是一對一對的對映 ”key=value“,key值 是無序,不重複的。value值可重複
訪問:可以map中key值轉為為set儲存,然後迭代這個set,用map.get(key)獲取value
也可以 轉換為entry物件 用迭代器迭代
Set集合排序
2017年10月03日 11:08:08閱讀數:4202TreeSet使用元素的自然順序對元素進行排序,或者根據建立set時提供的Comparator進行排序,具體取決於使用的構造方法。通俗一點來說,就是可以按照排序後的列表顯示,也可以按照指定的規則排序。
Set<String> set = new TreeSet<String>();
set.add("f");
set.add("a");
set.add("b");
set.add("c");
set.add("d");
set.add("e");
System.out.println(set);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
輸出:[a, b, c, d, e, f] ,按照排序後輸出
若想它倒序輸出,可以指定一個規則讓他倒序輸出
public class TreeSetTest3 {
public static void main(String[] args) {
Set<String> set = new TreeSet<String>(new MyComparator());
set.add("a");
set.add("b" );
set.add("c");
set.add("d");
set.add("e");
set.add("A");
for(Iterator<String> iterator = set.iterator();iterator.hasNext();){
System.out.print(iterator.next()+" ");
}
}
}
class MyComparator implements Comparator<String>{
@Override
public int compare(String o1, String o2) {
return o2.compareTo(o1);//降序排列
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
輸出:e d c b a A
如果Set集合中放入的是我們自己定義的一個類型別呢?
注意:一定要定義一個排序規則類實現Comparator介面,與上面的方法類似
public class TreeSetTest2 {
public static void main(String[] args) {
Set<Person> set = new TreeSet<Person>(new PersonComparator());
Person p1 = new Person(10);
Person p2 = new Person(20);
Person p3 = new Person(30);
Person p4 = new Person(40);
set.add(p1);
set.add(p2);
set.add(p3);
set.add(p4);
for(Iterator<Person> iterator = set.iterator();iterator.hasNext();){
System.out.print(iterator.next().score+" ");
}
}
}
class Person{
int score;
public Person(int score){
this.score = score;
}
public String toString(){
return String.valueOf(this.score);
}
}
class PersonComparator implements Comparator<Person>{
@Override
public int compare(Person o1, Person o2) {
return o1.score - o2.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
輸出:10 20 30 40
如果按照一個人的分數的倒序排列,只需要更改compare方法中的o2.score-o1.score
LinkedHashMap的特性:
LinkedHashMap的特性
LinkedHashMap的特性:
Linked內部含有一個private transient Entry header;來記錄元素插入的順序或者是元素被訪問的順序。利用這個線性結構的物件,可以幫助記錄entry加入的前後順序或者記錄entry被訪問的頻率(最少被訪問的entry靠前,最近訪問的entry靠後)。大致的過程如下:
new LinkedHashMap(10, 0.75, true);
其中前面兩個引數就是HashMap建構函式需要的引數,後面的true表明LinkedHashMap按照訪問的次序來排序(即accessOrder為true)。
按照訪問的次序來排序的含義:當呼叫LinkedHashMap的get(key)或者put(key, value)時,碰巧key在map中被包含,那麼LinkedHashMap會將key物件的entry放線上性結構的最後。
按照插入順序來排序的含義:呼叫get(key), 或者put(key, value)並不會對線性結構產生任何的影響。
正是因為LinkedHashMap提供按照訪問的次序來排序的功能,所以它才需要改寫HashMap的get(key)方法(HashMap不需要排序)和HashMap.Entry的recordAccess(HashMap)方法
public Object get(Object key) {
Entry e = (Entry)getEntry(key);
if (e == null)
return null;
e.recordAccess(this);
return e.value;
}
void recordAccess(HashMap m) {
LinkedHashMap lm = (LinkedHashMap)m;
if (lm.accessOrder) {
lm.modCount++;
remove();
addBefore(lm.header);
}
}
注意addBefore(lm.header)是將該entry放在header線性表的最後。(參考LinkedHashMap.Entry extends HashMap.Entry 比起HashMap.Entry多了before, after兩個域,是雙向的)
至於put(key, value)方法, LinkedHashMap不需要去改寫,用HashMap的就可以了,因為HashMap在其put(key, value)方法裡邊已經預留了e.recordAccess(this);
還有一個方法值得關注:
protected boolean removeEldestEntry(Map.Entry eldest) {
return false;
}
當呼叫put(key, value)的時候,HashMap判斷是否要自動增加map的size的作法是判斷是否超過threshold, LinkedHashMap則進行了擴充套件,如果removeEldestEntry方法return false;(預設的實現),那麼LinkedHashMap跟HashMap處理擴容的方式一致;如果removeEldestEntry返回true,那麼LinkedHashMap會自動刪掉最不常用的那個entry(也就是header線性表最前面的那個)。
這會造成嚴重的效能問題嗎?答案當然是否定的。因為在這兒的連結串列操作是常量級的。這也是LinkedHashMap/Set在這兒比TreeMap/Set效能更高的原因。
同樣,LinkedHashMap/Set也不是thread-safe的。如果在多執行緒下訪問,是需要進行外部同步,或者使用Collections.synchronizedMap()的方法包裝成一個thread-safe的Map/Set。
特別需要注意的是,在使用“訪問順序”時,讀取節點操作也是“結構變化”的操作。因為,這會改變元素遍歷的順序。所以,在使用LinkedHashMap的iterator()方法,遍歷元素時,如果其它執行緒有讀取操作,也要進行同步。否則,也會丟擲同其它fail-fast一樣的由於刪除或增加操作而引起的CurrentModificationException的例外。
最後,LinkedHashMap預設是使用插入順序的,如何構造一個訪問順序的LinkedHashMap呢?很簡單:public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) accessOrder = true 即可。
/**
* 電子墨水屏安卓端查詢學生課程按照排列順
序將資料儲存到list中
*/@Override
public List<String> couList(List<UserCourseEntity> tUserCours) throws ParseException {
List<String> list = new ArrayList<String>();
Set<String> timeSet = new LinkedHashSet<String>();
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
//遍歷集合將上課時間與第幾節課放進set中,定義Set<String> timeSet = new LinkedHashSet<String>();可以將set中的資料按照新增順序存放
for (UserCourseEntity userCourseEntity : tUserCours) {
String startTime = sdf.format(sdf.parse(userCourseEntity.getStartTime()));
String endTime = sdf.format(sdf.parse(userCourseEntity.getEndTime()));
String periodNum = userCourseEntity.getPeriodNum();
String time = startTime+"~"+endTime;
boolean res = timeSet.add(time+"-"+periodNum);
if (!res) {
continue;
}
}
//遍歷set集合與課程集合將第幾節課與對應課程鍵值對關聯定義LinkedHashMap<String,List<String>> map = new LinkedHashMap<String,List<String>>();也可以將資料按照新增順序存放
LinkedHashMap<String,List<String>> map = new LinkedHashMap<String,List<String>>();
for (String str : timeSet) {
for (UserCourseEntity course : tUserCours) {
String ts = sdf.format(sdf.parse(course.getStartTime()))+"~"+sdf.format(sdf.parse(course.getEndTime()))+"-"+course.getPeriodNum();
if(ts.equals(str)){
List<String> couList = map.get(ts);
if(couList==null){
couList = new ArrayList<String>();
}
couList.add(course.getCourseName());
map.put(ts, couList);
}
}
}
//遍歷map.keySet()與 map.get(key)分別按對應順序放入list中
for (String key : map.keySet()) {
String periodNum = key.split("-")[1];
String time = key.split("-")[0];
list.add(periodNum);
list.add(time);
for (String courseName : map.get(key)) {
list.add(courseName);
}
}
return list;
}
}
今天做統計時需要對X軸的地區按照地區程式碼(areaCode)進行排序,由於在構建XMLData使用的map來進行資料統計的,所以在統計過程中就需要對map進行排序。
一、簡單介紹Map
在講解Map排序之前,我們先來稍微瞭解下map。map是鍵值對的集合介面,它的實現類主要包括:HashMap,TreeMap,Hashtable以及LinkedHashMap等。其中這四者的區別如下(簡單介紹):
HashMap:我們最常用的Map,它根據key的HashCode 值來儲存資料,根據key可以直接獲取它的Value,同時它具有很快的訪問速度。HashMap最多隻允許一條記錄的key值為Null(多條會覆蓋);允許多條記錄的Value為 Null。非同步的。
TreeMap: 能夠把它儲存的記錄根據key排序,預設是按升序排序,也可以指定排序的比較器,當用Iterator 遍歷TreeMap時,得到的記錄是排過序的。TreeMap不允許key的值為null。非同步的。
Hashtable: 與 HashMap類似,不同的是:key和value的值均不允許為null;它支援執行緒的同步,即任一時刻只有一個執行緒能寫Hashtable,因此也導致了Hashtale在寫入時會比較慢。
LinkedHashMap: 儲存了記錄的插入順序,在用Iterator遍歷LinkedHashMap時,先得到的記錄肯定是先插入的.在遍歷的時候會比HashMap慢。key和value均允許為空,非同步的。
二、Map排序
TreeMap
TreeMap預設是升序的,如果我們需要改變排序方式,則需要使用比較器:Comparator。
Comparator可以對集合物件或者陣列進行排序的比較器介面,實現該介面的public compare(T o1,To2)
方法即可實現排序,該方法主要是根據第一個引數o1,小於、等於或者大於o2分別返回負整數、0或者正整數。如下:
public class TreeMapTest { public static void main(String[] args) { Map<String, String> map = new TreeMap<String, String>( new Comparator<String>() { public int compare(String obj1, String obj2) { // 降序排序 return obj2.compareTo(obj1); } }); map.put("c", "ccccc"); map.put("a", "aaaaa"); map.put("b", "bbbbb"); map.put("d", "ddddd"); Set<String> keySet = map.keySet(); Iterator<String> iter = keySet.iterator(); while (iter.hasNext()) { String key = iter.next(); System.out.println(key + ":" + map.get(key)); } } }
執行結果如下:
d:ddddd
c:ccccc
b:bbbbb
a:aaaaa
上面例子是對根據TreeMap的key值來進行排序的,但是有時我們需要根據TreeMap的value來進行排序。對value排序我們就需要藉助於Collections的sort(List<T> list, Comparator<? super T> c)方法,該方法根據指定比較器產生的順序對指定列表進行排序。但是有一個前提條件,那就是所有的元素都必須能夠根據所提供的比較器來進行比較。如下:
public class TreeMapTest { public static void main(String[] args) { Map<String, String> map = new TreeMap<String, String>(); map.put("d", "ddddd"); map.put("b", "bbbbb"); map.put("a", "aaaaa"); map.put("c", "ccccc"); //這裡將map.entrySet()轉換成list List<Map.Entry<String,String>> list = new ArrayList<Map.Entry<String,String>>(map.entrySet()); //然後通過比較器來實現排序 Collections.sort(list,new Comparator<Map.Entry<String,String>>() { //升序排序 public int compare(Entry<String, String> o1, Entry<String, String> o2) { return o1.getValue().compareTo(o2.getValue()); } }); for(Map.Entry<String,String> mapping:list){ System.out.println(mapping.getKey()+":"+mapping.getValue()); } } }
執行結果
a:aaaaa
b:bbbbb
c:ccccc
d:ddddd
HashMap
我們都是HashMap的值是沒有順序的,他是按照key的HashCode來實現的。對於這個無序的HashMap我們要怎麼來實現排序呢?參照TreeMap的value排序,我們一樣的也可以實現HashMap的排序。
public class HashMapTest { public static void main(String[] args) { Map<String, String> map = new HashMap<String, String>(); map.put("c", "ccccc"); map.put("a", "aaaaa"); map.put("b", "bbbbb"); map.put("d", "ddddd"); List<Map.Entry<String,String>> list = new ArrayList<Map.Entry<String,String>>(map.entrySet()); Collections.sort(list,new Comparator<Map.Entry<String,String>>() { //升序排序 public int compare(Entry<String, String> o1, Entry<String, String> o2) { return o1.getValue().compareTo(o2.getValue()); } }); for(Map.Entry<String,String> mapping:list){ System.out.println(mapping.getKey()+":"+mapping.getValue()); } } }
執行結果
a:aaaaa
b:bbbbb
c:ccccc
d:ddddd