compareTo的实现策略

1.compareTo用于TreeSet,而TreeSet个人认为最好用于读DB的结果集,将来可以基于compareTo的排序结果取subSet。写DB的时候,可以使用HashSet而不是TreeSet,因为写之前的结构不需要考虑排序与取子集。

2.compareTo如何实现:按照想要比较的字段的冲突出现的概率依次判断。
假设表的结构:memberid, locationid,type 并且memberid,locatonid是组合主键。这样一个memberid可以对应多条locationid的记录。
如果从DB中读出某个member的所有记录放到TreeSet,并且将来根据type排序,那么type需要第一个出现在compareTo里面,同时只有type,其它相同type的记录可能就添加不到treeset里,所以还需要拉上一个类似于identify的字段,当然就是locationid。
这样想要比较的字段就是type,locationid,根据冲突出现的可能性,当然是先type,后locationid。

示例: MemberLocationElement对象放到TreeSet中的compareTo的实现策略:先判断最可能相同的type值,然后再判断最不可能冲突的locationid。TreeSet主要用于读从DB读出结果集时使用。在写入的时候,需要保证locationid不同,可以使用HashSet来写。所以,TreeSet个人觉得最好的方式是读的时候使用。而不是希望它做add的操作。

    public static class MemberLocationElementComparator implements Comparator<MemberLocationElement>,Serializable{
        private static final long serialVersionUID = 1L;

        @Override
        public int compare(MemberLocationElement o1, MemberLocationElement o2)
        {
            if (o1 == null || o2 == null)
                return -1;
            if (o1.getType().getVal() == o2.getType().getVal())
            {
                return o1.getLocationid() - o2.getLocationid();
            }
            return o1.getType().getVal() - o2.getType().getVal();
        }
    }

 

又比如从DB读Person记录到TreeSet,Person包含fn以及ln二个属性分别表示first_name,last_name.  假设fn+ln构造复合主键。如果要读所有的用户记录到TreeSet
此时compareTo的字段应该是fn,ln,注意这里的ln并不是一个identify的字段,但是由于fn+ln是identify,按照冲突出现的概率,fn冲突的可能性更大,所以先比较。
比如加入李想,李晨, 不能因为加入李想就由于first_name=李而不让加入李晨,所以如果fn相等,可以接着比较ln。
对于不同的fn,当然可以加入到TreeSet,但是对于相同的fn,此时就需要接着比较last_name以防止不能加入。



又比如图片类PhotoInfo包含了blessed和uploaddate的值,blessed的值从0~7,如果实现一个2>1>6的排序,相同情况下再按uploaddate排序(最近的先显示)

比较器实现如下:

public static class TestComparator implements Comparator<PhotoInfo>, Serializable
    {
        private static final long serialVersionUID = 1L;
        public  static final Map<Integer, Integer> blessedIndMap       = new HashMap<Integer, Integer>();
        static
        {
            blessedIndMap.put(UserImage.S_BLESSED_GEO_PARENT,3);
            blessedIndMap.put(UserImage.S_BLESSED_GEO_ONLY,2);
            blessedIndMap.put(UserImage.S_BLESSED_PROPERTY_ONLY,1);
        }

        @Override
        public int compare(PhotoInfo o1, PhotoInfo o2)
        {
            if (o1 == null || o2 == null)
            {
                return -1;
            }
            int bind1 = getIndexByBlessed(o1.getBlessed());
            int bind2 = getIndexByBlessed(o2.getBlessed());
            if (bind1 == bind2)
            {
                //recently first show,因为默认都是升序,所以取负值。
                return -(o1.getUploadedDate().compareTo(o2.getUploadedDate()));
            }
            //blessed show order 2,1,6,other,因为默认都是升序,所以取负值。
            return -(bind1 - bind2);
        }
        
        public int getIndexByBlessed(int blessed)
        {
            return blessedIndMap.get(blessed) == null ? 0 : blessedIndMap.get(blessed);
        }
    }

对于List,使用比较器如下:Collections.sort(photoInfoList, new TestComparator());

 

3.特别强调Map通过comparator只能比较value,如果想让key也排序或者是做到有序Map,就只能使用LinkedHashMap,它支持按照添加的顺序排序。

 

4.TreeSet的接口划分及使用:
对于remove, removeAll这样的操作依赖于Element定义的equal方法。

对于add,addAll,headSet, tailSet,subSet这样操作依赖于compareTo方法。

取某个范围的结果集使用tailSet+headSet。subSet取的是半开半闭区间的结果集,不好操作。tailSet表示>=   headSet表示<

TreeSet是实现类,根据排序取范围的操作都定义在接口SortedSet中,建议使用SortedSet而不是具体类。

import java.util.Comparator;
import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;

public class TreeSetTest {

    /**
     * @param args
     */
   
    public enum Type{
        GOING(1),BEEN(2),GOING_THEN_BEEN(3);
        private int val;
        private Type(int val){
            this.val=val;
        }
        public int getVal() {
            return val;
        }
        public void setVal(int val) {
            this.val = val;
        }
    }
    public static class Element{
        private int memeberid;
        private int locationid;
        private Type type;
        public Element(){}
        public int getMemeberid() {
            return memeberid;
        }
        public void setMemeberid(int memeberid) {
            this.memeberid = memeberid;
        }
        public int getLocationid() {
            return locationid;
        }
        public void setLocationid(int locationid) {
            this.locationid = locationid;
        }
        public Type getType() {
            return type;
        }
        public void setType(Type type) {
            this.type = type;
        }
        public Element(int memeberid, int locationid, Type type) {
            super();
            this.memeberid = memeberid;
            this.locationid = locationid;
            this.type = type;
        }
        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + locationid;
            result = prime * result + memeberid;
            return result;
        }
        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            Element other = (Element) obj;
            if (locationid != other.locationid)
                return false;
            if (memeberid != other.memeberid)
                return false;
            return true;
        }
       
    }
    public static void main(String[] args) {
        TreeSet<Element> elements=new TreeSet<Element>(new Comparator<Element>() {
           
            @Override
            public int compare(Element o1, Element o2) {
                if(o1.getType().getVal()==o2.getType().getVal()){
                    return o1.getLocationid()-o2.getLocationid();
                }
                return o1.getType().getVal()-o2.getType().getVal();
            }
        });
        Element e1=new Element(111111, 294211, Type.GOING);
        Element e2=new Element(111111, 294212, Type.BEEN);
        Element e3=new Element(111111, 294213, Type.BEEN);
        Element e4=new Element(111111, 294214, Type.GOING_THEN_BEEN);
       
        elements.add(e1);
        elements.add(e2);
        elements.add(e3);
        elements.add(e4);
        
        
        loadSet(elements);
        
        System.out.println("-----------------------");
        Element from=new Element();
        from.setType(Type.GOING);
       
        Element to=new Element();
        to.setType(Type.GOING_THEN_BEEN);
       
        Element too=new Element();
        too.setType(Type.BEEN);
       
        Set<Element> subSet=elements.tailSet(too).headSet(to);
//      Set<Element> subSet=elements.tailSet(to);
//      Set<Element> subSet=elements.tailSet(too);
//      Set<Element> subSet=elements.subSet(from,Boolean.FALSE, to,Boolean.FALSE);
        
        loadSet(subSet);

        System.out.println("-------------------------");
        
        HashSet<Element> rmset=new HashSet<Element>();
        e2.setType(Type.GOING_THEN_BEEN);
        rmset.add(e2);
        e3.setType(Type.GOING_THEN_BEEN);
        rmset.add(e3);
        //其实是逐个调用remove方法,remove方法的根据是 如果此 set 中包含满足 (o==null ? e==null : o.equals(e)) 的元素 e,则移除它。可以看到remove这样不涉及到排序的操作equal是起作用的。
        elements.removeAll(rmset);
        elements.addAll(rmset);
        loadSet(elements);
    }
    private static void loadSet(Set<Element> set)
    {
        for (Element element : set) {
            System.out.println(element.locationid+"|"+element.getType().name());
        }
    }

}
 
posted @ 2012-11-07 10:30  highriver  阅读(854)  评论(0编辑  收藏  举报