Как отсортировать Map по значению
Короткий ответ
Отсортируйте пары entrySet() через Map.Entry.comparingByValue() и соберите в LinkedHashMap, который сохранит порядок:
void main() {
Map<String, Integer> scores = Map.of("Anna", 82, "Oleg", 95, "Boris", 67);
Map<String, Integer> sorted = scores.entrySet().stream()
.sorted(Map.Entry.comparingByValue())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> a, LinkedHashMap::new));
IO.println(sorted);
}Результат:
{Boris=67, Anna=82, Oleg=95}По убыванию
Передайте в comparingByValue() обратный компаратор:
void main() {
Map<String, Integer> scores = Map.of("Anna", 82, "Oleg", 95, "Boris", 67);
scores.entrySet().stream()
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
.forEach(e -> IO.println(e.getKey() + " " + e.getValue()));
}Результат:
Oleg 95
Anna 82
Boris 67Топ-N
Добавьте limit(), чтобы получить несколько лучших:
void main() {
Map<String, Integer> views = Map.of("home", 500, "blog", 320, "about", 40, "shop", 410);
var top = views.entrySet().stream()
.sorted(Map.Entry.<String, Integer>comparingByValue().reversed())
.limit(2)
.map(Map.Entry::getKey)
.toList();
IO.println(top);
}Результат:
[home, shop]Частая ошибка
Собрать отсортированный поток обычным Collectors.toMap(). Он создаёт HashMap, и порядок снова теряется:
void main() {
Map<String, Integer> scores = Map.of("Anna", 82, "Oleg", 95, "Boris", 67);
var result = scores.entrySet().stream()
.sorted(Map.Entry.comparingByValue())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
IO.println(result);
}Результат:
{Boris=67, Oleg=95, Anna=82}Всегда передавайте LinkedHashMap::new четвёртым аргументом.
Функции из этого ответа
- Map.Entry — Одна пара «ключ — значение» словаря.
- Collectors.toMap() — Сборщик, который строит словарь из элементов потока.
- LinkedHashMap — Словарь, который помнит порядок добавления ключей.
- Map.entrySet() — Возвращает все пары «ключ — значение» для обхода.