排序比較的實用(Comparable & Comparator )


在 Collections 有許多排序比較等等的方法已經寫好,基本類型的比較可以直接使用,如

   1:          ArrayList al = new ArrayList();
   2:          
   3:          for(int i=0; i<10; i++){
   4:          
   5:              Random r = new Random();
   6:              al.add(r.nextInt(1000));
   7:          }
   8:          
   9:          Collections.sort(al);


在 al 中的元素將會由小到大排好,但是如果 al 中的元素並不是基本類型,而是自創類別,而想比較的是自創類別中的某個屬性值,那麼可以實作 Comparable 介面,再覆寫 compareTo 方法,如下

AccountDetail.java

   1:  package com.example.helloworld;
   2:   
   3:  import java.util.Comparator;
   4:   
   5:  public class AccountDetail implements Comparable<Object>{
   6:   
   7:      static int dataCount;
   8:      public String time;
   9:      public String money;
  10:      public String remark;
  11:      
  12:      public AccountDetail(){
  13:          dataCount++;
  14:          time = "0000/00/00";
  15:          money = "0";
  16:          remark = "0";
  17:      }
  18:      
  19:      public AccountDetail(String time,String money,String type){
  20:          dataCount++;
  21:          this.time = time;
  22:          this.money = money;
  23:          this.remark = type;
  24:      }
  25:   
  26:      @Override
  27:      public int compareTo(Object another) {
  28:          // TODO Auto-generated method stub
  29:          
  30:          AccountDetail adAnother = (AccountDetail)another;
  31:          
  32:          if(Integer.valueOf(this.money)>Integer.valueOf(adAnother.money))
  33:          {
  34:              return 1;// move element back
  35:          }
  36:          else if(Integer.valueOf(this.money)<Integer.valueOf(adAnother.money)){
  37:              
  38:              return -1;//move element forward
  39:          }
  40:          else{
  41:              return 0;
  42:          }
  43:          
  44:          
  45:      }
  46:      
  47:  }
  48:   

AccountDetail 裡面有 3 個屬性,分別為 time , money , remark , 在第 5 行實作 Comparable 介面, 接著第 27 行覆寫 compareTo 方法, 方法裡面就寫出自訂的比較規則, 只要注意回傳值,1 代表往前排, -1 代表往後排,這段程式碼就代表比較 money 並由小排到大,最後使用的方式如下

   1:          ArrayList<AccountDetail> al = new ArrayList<AccountDetail>();
                
               for(int i=0; i<10 ;i++){
   2:              
   3:              Random r = new Random();
   4:              
   5:              al.add(new AccountDetail("testtime",""+r.nextInt(1000)+i,"testremark"));
   6:          }
   7:          
   8:          Collections.sort(al);

第 1 ~ 6 行建立 ArrayList al, 最後第 8 行排序,就這麼簡單,不過使用 Comparable 介面的缺點是只能使用單種排序,如果還想針對 time , remark 做排序,可以使用 Comparator 介面,好處除了可對多種數值做排序外,也不必綁定在 AccountDetail 類別中,你可以把它封裝出來(不過我還是寫在一起)

AccountDetail.java

   1:  package com.example.helloworld;
   2:   
   3:  import java.util.Comparator;
   4:   
   5:  import FoXxLib.FP;
   6:   
   7:  public class AccountDetail 
   8:  //implements Comparable<Object>
   9:  {
  10:   
  11:      static int dataCount;
  12:      public String time;
  13:      public String money;
  14:      public String remark;
  15:      
  16:      public AccountDetail(){
  17:          dataCount++;
  18:          time = "0000/00/00";
  19:          money = "0";
  20:          remark = "0";
  21:      }
  22:      
  23:      public AccountDetail(String time,String money,String type){
  24:          dataCount++;
  25:          this.time = time;
  26:          this.money = money;
  27:          this.remark = type;
  28:      }
  29:   
  30:  //    @Override
  31:  //    public int compareTo(Object another) {
  32:  //        // TODO Auto-generated method stub
  33:  //        
  34:  //        AccountDetail adAnother = (AccountDetail)another;
  35:  //        
  36:  //        if(Integer.valueOf(this.money)>Integer.valueOf(adAnother.money))
  37:  //        {
  38:  //            return 1;// back
  39:  //        }
  40:  //        else if(Integer.valueOf(this.money)<Integer.valueOf(adAnother.money)){
  41:  //            
  42:  //            return -1;//forward
  43:  //        }
  44:  //        else{
  45:  //            return 0;
  46:  //        }
  47:  //        
  48:  //        
  49:  //    }
  50:      
  51:      public MoneyComparator moneyComp(){
  52:          
  53:          MoneyComparator mc = new MoneyComparator();
  54:          
  55:          return mc;
  56:      }
  57:      
  58:      public TimeComparator timeComp(){
  59:          
  60:          TimeComparator tc = new TimeComparator();
  61:          
  62:          return tc;
  63:      }
  64:  }
  65:   
  66:  class MoneyComparator implements Comparator<Object>{
  67:   
  68:      @Override
  69:      public int compare(Object lhs, Object rhs) {
  70:          // TODO Auto-generated method stub
  71:          AccountDetail ad1 = (AccountDetail)lhs;
  72:          AccountDetail ad2 = (AccountDetail)rhs;
  73:          if(Integer.valueOf(ad1.money)>Integer.valueOf(ad2.money)){
  74:              return 1;
  75:          }
  76:          else if(Integer.valueOf(ad1.money)<Integer.valueOf(ad2.money)){
  77:              return -1;
  78:          }
  79:          else{
  80:              return 0;
  81:          }
  82:      }
  83:      
  84:  }
  85:   
  86:  class TimeComparator implements Comparator<Object>{
  87:   
  88:      @Override
  89:      public int compare(Object lhs, Object rhs) {
  90:          // TODO Auto-generated method stub
  91:          int tempReturn =0;
  92:          AccountDetail ad1 = (AccountDetail)lhs;
  93:          AccountDetail ad2 = (AccountDetail)rhs;
  94:          
  95:          String[] tempstr1 = ad1.time.split("[/]");
  96:          int[] tempint1 = new int[tempstr1.length];
  97:          for(int i=0; i<tempstr1.length; i++){
  98:              tempint1[i] = Integer.valueOf(tempstr1[i]);
  99:  //            FP.p(""+tempint1[i]);
 100:          }
 101:          
 102:          String[] tempstr2 = ad2.time.split("[/]");
 103:          int[] tempint2 = new int[tempstr2.length];
 104:          for(int i=0; i<tempstr2.length; i++){
 105:              tempint2[i] = Integer.valueOf(tempstr2[i]);
 106:  //            FP.p(""+tempint2[i]);
 107:          }
 108:          
 109:          for(int i=0; i<tempint1.length; i++){
 110:              
 111:              if(tempint1[i]>tempint2[i]){
 112:                  tempReturn = -1;
 113:                  break;
 114:              }
 115:              else if(tempint1[i]<tempint2[i]){
 116:                  tempReturn = 1;
 117:                  break;
 118:              }
 119:              else if(tempint1[i]==tempint2[i])
 120:              {
 121:                  tempReturn =0;
 122:              }
 123:          }
 124:          
 125:              return tempReturn;
 126:   
 127:      }
 128:      
 129:  }
 130:   

先把原先使用 Comparator 介面 的部分註解掉(第 8 行, 第 30 ~ 49 行)
第 51 ~ 56 行建立並回傳 money 的比較器
第 58 ~ 63 行建立並回傳 time 的比較器
第 66 ~ 84 行為 money 比較器的定義, 先實作 Comparator 介面
第 69 行覆寫 compare 方法, lhs 和 rhs 各為比較的物件,至於 compare 的內容就自己定義了
第 86 ~ 129 行為 time 比較器的定義,由於 time 包含了年月日,必須先切割字串,再放入陣列中等待比較,第 109 ~ 123 行為比較的方法

最後使用的方式如下

   1:  Collections.sort(al, al.get(0).timeComp());

第 1 個參數為比較的內容,第 2 個參數為比較器, timeComp 會回傳 time 比較器,當然你也可以改為 al.get(0).moneyComp() , 來比較 money

注意事項:
1.如果使用 Comparator 介面,且和要比較的容器類別綁在一起(就是上述的 AccountDetail.java),必須注意當沒有產生任何元素,還要排序時,會出現錯誤,所以排序類別還是拆開比較好如下

AD_Sort.java

   1:  package com.example.helloworld;
   2:   
   3:  import java.util.Comparator;
   4:   
   5:  public abstract class AD_Sort implements Comparator<Object>{
   6:   
   7:  }
   8:   
   9:  class MoneyComparator extends AD_Sort{
  10:   
  11:      @Override
  12:      public int compare(Object lhs, Object rhs) {
  13:          // TODO Auto-generated method stub
  14:          AccountDetail ad1 = (AccountDetail)lhs;
  15:          AccountDetail ad2 = (AccountDetail)rhs;
  16:          if(Integer.valueOf(ad1.money)>Integer.valueOf(ad2.money)){
  17:              return -1;
  18:          }
  19:          else if(Integer.valueOf(ad1.money)<Integer.valueOf(ad2.money)){
  20:              return 1;
  21:          }
  22:          else{
  23:              return 0;
  24:          }
  25:      }
  26:      
  27:  }
  28:   
  29:  class TimeComparator extends AD_Sort{
  30:   
  31:      @Override
  32:      public int compare(Object lhs, Object rhs) {
  33:          // TODO Auto-generated method stub
  34:          int tempReturn =0;
  35:          AccountDetail ad1 = (AccountDetail)lhs;
  36:          AccountDetail ad2 = (AccountDetail)rhs;
  37:          
  38:          String[] tempstr1 = ad1.time.split("[/]");
  39:          int[] tempint1 = new int[tempstr1.length];
  40:          for(int i=0; i<tempstr1.length; i++){
  41:              tempint1[i] = Integer.valueOf(tempstr1[i]);
  42:  //            FP.p(""+tempint1[i]);
  43:          }
  44:          
  45:          String[] tempstr2 = ad2.time.split("[/]");
  46:          int[] tempint2 = new int[tempstr2.length];
  47:          for(int i=0; i<tempstr2.length; i++){
  48:              tempint2[i] = Integer.valueOf(tempstr2[i]);
  49:  //            FP.p(""+tempint2[i]);
  50:          }
  51:          
  52:          for(int i=0; i<tempint1.length; i++){
  53:              
  54:              if(tempint1[i]>tempint2[i]){
  55:                  tempReturn = -1;
  56:                  break;
  57:              }
  58:              else if(tempint1[i]<tempint2[i]){
  59:                  tempReturn = 1;
  60:                  break;
  61:              }
  62:              else if(tempint1[i]==tempint2[i])
  63:              {
  64:                  tempReturn =0;
  65:              }
  66:          }
  67:          
  68:              return tempReturn;
  69:   
  70:      }
  71:      
  72:  }

然後使用的方式為

   1:          AD_Sort ads;
   2:          ads = new MoneyComparator();
   3:  //        ads = new TimeComparator();
   4:          Collections.sort(al, ads);

第 2 ~ 3 為多型的使用