这篇文章主要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()的比较。