Сортировка мапы по убыванию частоты повторения слов
Есть метод, который читает строки с файла, и выводит повторяющиеся слова и их количество. Нужно отсортировать по убыванию частоты повторения.
Пример:
the 4
is 3
sunny 2
day 1
Код:
public static void frequencyWordCounter(String url) throws IOException {
File file = new File(url);
InputStream inputFile = new FileInputStream(file);
Scanner scanner = new Scanner(inputFile);
String phrase = "";
while (scanner.hasNextLine()) {
phrase += scanner.nextLine();
}
inputFile.close();
String[] words = phrase.toLowerCase().split("\\s+");
String lowerCase = phrase.toLowerCase();
Map<String, Integer> wordCountTable = new HashMap<>();
int minWordLength = 0;
for (String word : words) {
String uniqueWord = word.toLowerCase();
if (uniqueWord.length() > minWordLength) {
if (wordCountTable.containsKey(uniqueWord)) {
wordCountTable.replace(uniqueWord, wordCountTable.get(uniqueWord),
wordCountTable.get(uniqueWord).intValue() + 1);
} else {
wordCountTable.put(uniqueWord, 1);
}
}
}
wordCountTable.entrySet().forEach(entry -> {
System.out.println(entry.getKey() + " " + entry.getValue());
});
}
Ответы (1 шт):
Автор решения: Nowhere Man
→ Ссылка
Конкретно в данном случае для сортировки содержимого мапы слов по убыванию частот достаточно отсортировать поток (стрим) пар "ключ-значение", используя Stream API (Stream::sorted) и Map.Entry.comparingByValue:
wordCountTable.entrySet().stream() // Stream<Map.Entry<>>
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
.forEach(entry -> {
System.out.println(entry.getKey() + " " + entry.getValue());
});
Если надо дополнительно отсортировать слова с одинаковыми частотами по алфавиту, это можно будет выполнить так:
wordCountTable.entrySet().stream() // Stream<Map.Entry<>>
.sorted(Map.Entry.<String, Integer>comparingByValue(Comparator.reverseOrder())
.thenComparing(Map.Entry::getKey)
)
Также в представленном коде можно улучшить чтение данных и получение собственно мапы частот, по примеру реализации в ответе, добавив фильтр по длине слова и сортировку по убыванию:
public void printWordFrequencies(String path, int minLength) throws IOException {
try (Stream<String> input = Files.lines(Paths.get(path))) {
input
.flatMap(str -> Arrays.stream(str.toLowerCase().split("\\P{L}+"))) // поток слов
.filter(word -> word.length() >= minLength) // фильтр по длине
.collect(Collectors.groupingBy(
word -> word,
Collectors.summingInt(word -> 1)
)) // Map<String, Integer>
.entrySet()
.stream()
.sorted(Map.Entry.comparingByValue(
Comparator.reverseOrder()
))
.forEach(entry -> {
System.out.println(entry.getKey() + " " + entry.getValue());
});
}
}