Reputation: 519
I have the following code below to sort words based on their alphabetical order and their frequency. I understand the main functionality is in Comparator
class that does custom sorting based on frequency
and alphabetical order of words in reverse order (not default Java order, which is the ascending order).
Question: I am just confused about inner working of Comparator
please? Not sure why freq1-freq2
was used but word2.compareTo(word1)
and not word2.compareTo(word1)
? The requirement is, if 2 words have the same frequency, then we should sort in ascending fashion, but if the two words do not have the same frequency, then the word with largest frequency comes first in priority queue below. I though this implementation of Comparator
will cause priority queue to be min priority queue? Please correct me if I am wrong?
import java.util.*;
class TopKWords{
public List<String> topWords(String[] words, int k) {
Map<String, Integer> pair = new HashMap<>();
for(String word: words){
pair.put(word, pair.getOrDefault(word, 0) + 1);
}
PriorityQueue<String> pq = new PriorityQueue<>(
new Comparator<String>(){
@Override
public int compare(String word1, String word2){
int freq1 = pair.get(word1);
int freq2 = pair.get(word2);
if(freq1 == freq2) return word2.compareTo(word1);
return freq1 - freq2;
}
}
);
for(Map.Entry<String, Integer> entry: pair.entrySet()){
pq.add(entry.getKey());
if(pq.size() > k) pq.poll();
}
List<String> list = new ArrayList<>();
while(!pq.isEmpty()){
list.add(pq.poll());
}
Collections.reverse(list);
return list;
}
}
Upvotes: 0
Views: 678
Reputation: 56
The requirement is, if 2 words have the same frequency, then we should sort in ascending fashion, but if the two words do not have the same frequency, then the word with largest frequency comes first in priority queue below.
There are two cases.
1st Case
return freq1 - freq2;
It ensures ascending sort. But later it is reversed to ensure descending sort. It is for the first case.
2nd Case
word2.compareTo(word1)
It ensures descending sort (second compared with first). Later reversed to ensure ascending sort. It is the second case.
Simply put, as for 2 cases sorting is different that's why for 1 case, freq1-freq2 is used and for another one word2.compareTo(word1) is used. If both had same sorting then we would have used, freq1-freq2 and word1.compareTo(word2).
Upvotes: 1
Reputation: 1760
I don't know if this is the most efficient way to do it, but
public class FreqComp implements Comparator<String> {
private Map<String, Integer> countMap = new HashMap<>();
public FreqComp(String [] data) {
//initialize the internal map to keep word counts
for (String word : data) {
countMap.merge(word, 1, (a, b) -> a+b);
}
}
@Override
public int compare(String o1, String o2) {
//First get the counts and sort in reverse so the higher number comes first
Integer cnt1 = countMap.get(o1);
Integer cnt2 = countMap.get(o2);
int val = cnt2.compareTo(cnt1);
if (val == 0) {
//If it's the same word count, sort alphabetically
val = o1.compareTo(o2);
}
return val;
}
}
and the use
public static void main(String [] args) {
String [] words = {"a", "b", "c", "d", "b", "c", "d", "c", "d", "d", "e", "e", "e", "e"};
Arrays.sort(words, new FreqComp(words));
System.out.println(Arrays.toString(words));
}
Upvotes: 1