您的位置:首页 > 其它

How to first sort by one attribute, if equal, then sort by another attribute.

2015-09-28 13:12 405 查看
这篇文章主要demo,如何来按照两个字段进行sort。

场景1

有一个list of classes,每个class中的attribute 1是String name, attribute 2是 Int age。现在假设需求是先按照name 字母顺序升序排序,加入两个人同名同姓,再按照age升序排序。 在这样的场景下,就需要使用comparator去对2个字段进行排序。

场景2

有一个map,map中key是单词 String word,value是单词的词频 int count。需要对map中的单词按照count进行降序排序,如果词频一样,就按照String word单词本身进行字母顺序升序排序。

上面的场景2和场景1本质是类似的,都会用到sort。现在就来看看更麻烦一些的场景2如何写。

public class DemoOne {
    public void sortWord(String inputFileName) throws Exception{
        String line;
        HashMap<String, Integer> frequentMap = new HashMap<String, Integer> ();

        // 1 read
        // read from a file and load the file into a map.
        try (BufferedReader br = new BufferedReader(new FileReader(inputFileName))) {
            while ((line = br.readLine()) != null) {
                if (frequentMap.containsKey(line) ) {
                    frequentMap.put(line, frequentMap.get(line) + 1);
                } else {
                    frequentMap.put(line, 1);
                }
            }
        }

        // 2 sort
        // first by word count(the second attribute),
        // then by word alphabetical order(the first attribute);
        Comparator<Map.Entry<String, Integer> > comparator = new Comparator<Map.Entry<String, Integer>>() {
            @Override
            public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
                if (o1.getValue() == o2.getValue()) {
                    return o1.getKey().compareTo(o2.getKey());
                } else {
                    return o2.getValue().compareTo(o1.getValue());
                }
            }
        };
        Queue<Map.Entry<String, Integer> > heap = new PriorityQueue<Map.Entry<String, Integer> >(100, comparator);
        for (Map.Entry<String, Integer> each : frequentMap.entrySet()) {
            //System.out.println( each.getValue() + ", " + each.getKey());
            heap.add(each);
        }

        //3 output after sort
        Map.Entry<String, Integer> tempEntry = null;
        while (!heap.isEmpty()) {
        //for (int i = 0; i < heap.size(); ++i) { //这是个易错的BUG,heap的size()一直再变化,所以用它作为循环条件将会悲剧。
            //System.out.println("A");
            tempEntry = heap.poll();
            System.out.println( tempEntry.getValue() + ", " + tempEntry.getKey());
        }
    }
    public static void main  (String [] args)throws Exception {
        String inputFileName = "./input.txt";
        DemoOne demoOne = new DemoOne();
        demoOne.sortWord(inputFileName);
    }
}


Sample Input

this
cake
is
a
nice
nice
moon
cake


Sample Output

2, cake
2, nice
1, a
1, is
1, moon
1, this


上面代码中,重点是comparator的写法。在comparator的这段代码中

public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
                if (o1.getValue() == o2.getValue()) {
                    return o1.getKey().compareTo(o2.getKey());
                } else {
                    return o2.getValue().compareTo(o1.getValue());
                }
            }
先比较Map中存的<Key, Value> pair中的value, 也就是先比较<String Word, Integer Count> 中的count, 如果不相等,那么count的比较结果就是comparator的比较结果, 也就是,

(1) 如果o1.count 较o2.count小,则返回正数(注意这里是降序排序,所以正好和升序情况相反),所以是o1.getValue()和o2.getValue()的比较。

(2) 如果o1.count较o2.count大,则返回负数(注意这里是降序排序,所以正好和升序情况相反),所以是o1.getValue()和o2.getValue()的比较。

(3) 如果二者相等,则比较o1和o2的word的字母顺序,所以所以o1.getKey()和o2.getKey()的比较。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: