3.多列排序問題
3.1排序條件的數量
我們知道,SQL語句能夠實現強大的排序功能,能夠按照不同字段的排列進行排序,也能夠按照升序,降序排序。比如下面的語句。
order by field1 asc, field2 asc, field3 desc。
這個排序條件按照field1的升序,field2的升序,field3的降序排序。
注意,排在前面的字段具有較高的優先級。
比如,兩條紀錄A和B,滿足如下條件:
(1)A.field1 > B.field1,(2)A.field2 < B.field2。
這時如果按照order by field1, field2語句排序,那么 A > B。
如果上述條件中的(1)A.field1 > B.field1變化為A.field1 == B.field1。這時,條件(2)就會起作用。這時,A < B。
我們來看看在Java中如何實現這種靈活而強大的排序。
我們還是以上一節的Record類為例。Record類有3個字段,我們來看一看,有多少種可能的排序條件。
(1)按field1排序。(2)按field2排序。(3)按field3排序。(4)按field1,field2排序。(5)按field1升序,按field2降序排序…...
各種排序條件的排列組合,大概共有30種。而且,隨著字段個數的增長,排序條件的個數呈冪級數的增長。
按照上一節的sort和Comparator方法,如果我們需要達到按照任意條件進行排序的目的,那么我們需要為每一個排序條件提供一個Comparator,我們需要30個Comparator類。:-)
當然,我們不會這么做,我們能夠進一步提取這個問題中的相同重復部分,優化我們的解決方案。
3.2 問題分析
我們來分析這個問題中變化的部分和不變的部分。
上面所有的排序條件中,不變的部分有3部分:
(1)A.field1和B.field1的比較,
(2)A.field2和B.field2的比較,
(3)A.field3和B.field3的比較;
變化的部分有兩部分,
(1)這三種比較條件的任意組合排列,
(2)升序和降序。
根據這段分析,我們引入兩個類,ReverseComparator類和CompositeComparator類。
CompositeComparator類用來解決字段的組合排列問題。
ReverseComparator類用來解決字段的升序、降序問題。
3.3 ReverseComparator類的代碼
import java.util.Comparator;
public class ReverseComparator implements Comparator{
/** the original comparator*/
private Comparator originalComparator = null;
/** constructor takes a comparator as parameter */
public ReverseComparator(Comparator comparator){
originalComparator = comparator;
}
/** reverse the result of the original comparator */
public int compare(Object o1, Object o2){
return - originalComparator.compare(o1, o2);
}
}
3.4 CompositeComparator類的代碼
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.LinkedList;
public class CompositeComparator implements Comparator{
/** in the condition list, comparators' priority decrease from head to tail */
private List comparators = new LinkedList();
/** get the comparators, you can manipulate it as need.*/
public List getComparators(){
return comparators;
}
/** add a batch of comparators to the condition list */
public void addComparators(Comparator[] comparatorArray){
if(comparatorArray == null){
return;
}
for(int i = 0; i < comparatorArray.length; i++){
comparators.add(comparatorArray[i]);
}
}
/** compare by the priority */
public int compare(Object o1, Object o2){
for(Iterator iterator = comparators.iterator(); iterator.hasNext();){
Comparator comparator = (Comparator)iterator.next();
int result = comparator.compare(o1, o2);
if(result != 0){
return result;
}
}
return 0;
}
}
3.5 Comparator的組合應用
這一節講述上面兩個類的用法。
對應前面的排序問題,我們只需要3個Comparator類:
(1)Field1Comaprator;
(2)Field2Comaprator;
(3)Field3Comaprator。
下面舉例說明,如何組合這些Comparator實現不同的排序條件。
(1)order by field1, field2
CompoiComparator myComparator = new CompoiComparator();
myComparator. addComparators(
new Comparator[]{
new Field1Comaprator (), new Field2Comaprator ()};
);
// records is a list of Record
Collections.sort(records, myComparator);
(1)order by field1 desc, field2
CompoiComparator myComparator = new CompoiComparator();
myComparator. addComparators(
new Comparator[]{
new ReverseComparator(new Field1Comaprator ()),
new Field2Comaprator ()};
);
// records is a list of Record
Collections.sort(records, myComparator);
這里提供的ReverseComparator類和CompositeComparator類都采用了Decorator Pattern。
CompositeComparator類同時也是Composite Pattern。
4.過濾條件的排列組合
過濾條件問題也屬于條件組合問題的范疇。比如JDK提供的java.io.File類提供了一個文件過濾方法listFile(FileFilter),用戶可以定制不同的FileFilter,實現不同的過濾條件,比如文件時間在某個范圍內;文件后綴名,文件名符合某種模式;是目錄,還是文件,等等。
同樣,我們可以應用上述的解決方法,實現靈活的過濾條件組合――用一個CompositeFilter類任意組合過濾條件,用一個ReverseFilter類作為排除條件。
4.1 CompositeFilter類的代碼
import java.io.FileFilter;
import java.io.File;
import java.util.Iterator;
import java.util.List;
import java.util.LinkedList;
public class CompositeFilter implements FileFilter {
/** in the filter list, every condition should be met. */
private List filters = new LinkedList();
/** get the filters, you can manipulate it as need.*/
public List getFilters(){
return filters;
}
/** add a batch of filters to the condition list */
public void addComparators(FileFilter[] filterArray){
if(filterArray == null){
return;
}
for(int i = 0; i < filterArray.length; i++){
filters.add(filterArray[i]);
}
}
/** must meet all the filter condition */
public boolean accept(File pathname) {
for(Iterator iterator = filters.iterator(); iterator.hasNext();){
FileFilter filter = (FileFilter)iterator.next();
boolean result = filter.accept(pathname);
// if any condition can not be met, return false.
if(result == false){
return false;
}
}
// all conditions are met, return true.
return true;
}
}
4.2 ReverseFilter類的代碼
import java.util.Comparator;
public class ReverseComparator implements Comparator{
/** the original comparator*/
private Comparator originalComparator = null;
/** constructor takes a comparator as parameter */
public ReverseComparator(Comparator comparator){
originalComparator = comparator;
}
/** reverse the result of the original comparator */
public int compare(Object o1, Object o2){
return - originalComparator.compare(o1, o2);
}
}