Sorting words in order of frequency? (least to greatest)
java, sorting
Solution
First of all your usage of `scanner.next()` seems incorrect. `next()` will return the next word and move onto next one every time you call it, therefore the following code:
if(scanner.next() == null){ ... }
and also
scanner.next().replaceAll("[^A-Za-z0-9]"," ");
scanner.next().toLowerCase();
will consume and then just throw away words. What you probably want to do is:
String word = scanner.next().replaceAll("[^A-Za-z0-9]"," ").toLowerCase();
at the beginning of your `while` loop, so that the changes to your word are saved in the `word` variable, and not just thrown away.
Secondly, the usage of the `wordCount` map is slightly broken. What you want to do is to check if the `word` is already in the map to decide what word count to set. To do this, instead of checking for `scanner.next() == null` you should look in the map, for example:
if(!wordCount.containsKey(word)){
//no count registered for the word yet
wordCount.put(word, 1);
}else{
wordCount.put(word, wordCount.get(word) + 1);
}
alternatively you can do this:
Integer count = wordCount.get(word);
if(count == null){
//no count registered for the word yet
wordCount.put(word, 1);
}else{
wordCount.put(word, count+1);
}
I would prefer this approach, because it's a bit cleaner, and does only one map look-up per word, whereas the first approach sometimes does two look-ups.
Now, to get a list of words in descending order of frequencies, you can convert your map to a list first, then apply `Collections.sort()` as was suggested in this post. Below is a simplified version suited to your needs:
static List<String> getWordInDescendingFreqOrder(Map<String, Integer> wordCount) {
// Convert map to list of <String,Integer> entries
List<Map.Entry<String, Integer>> list =
new ArrayList<Map.Entry<String, Integer>>(wordCount.entrySet());
// Sort list by integer values
Collections.sort(list, new Comparator<Map.Entry<String, Integer>>() {
public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
// compare o2 to o1, instead of o1 to o2, to get descending freq. order
return (o2.getValue()).compareTo(o1.getValue());
}
});
// Populate the result into a list
List<String> result = new ArrayList<String>();
for (Map.Entry<String, Integer> entry : list) {
result.add(entry.getKey());
}
return result;
}
Hope this helps.
Edit: Changed the comparison function as suggested by @dragon66. Thanks.
Problem
does any one have any idea how to sort a list of words in the order of their frequency (least to greatest) using the built in `collection.sort` and a `comparator<string>` interface? I already have a method that gets the count of a certain word in the text file. Now, I just need to create a method that compares the counts of each word and then puts them in a list sorted by the least frequency to the greatest. Any ideas and tips would be very much appreciated. I'm having trouble getting started on this particular method. ``` public class Parser implements Comparator<String> { public Map<String, Integer> wordCount; void parse(String filename) throws IOException { File file = new File(filename); Scanner scanner = new Scanner(file); //mapping of string -> integer (word -> frequency) Map<String, Integer> wordCount = new HashMap<String, Integer>(); //iterates through each word in the text file while(scanner.hasNext()) { String word = scanner.next(); if (scanner.next()==null) { wordCount.put(word, 1); } else { wordCount.put(word, wordCount.get(word) + 1);; } } scanner.next().replaceAll("[^A-Za-z0-9]"," "); scanner.next().toLowerCase(); } public int getCount(String word) { return wordCount.get(word); } public int compare(String w1, String w2) { return getCount(w1) - getCount(w2); } //this method should return a list of words in order of frequency from least to greatest public List<String> getWordsInOrderOfFrequency() { List<Integer> wordsByCount = new ArrayList<Integer>(wordCount.values()); //this part is unfinished.. the part i'm having trouble sorting the word frequencies List<String> result = new ArrayList<String>(); } } ```