Encodera

Thanks for reading!

Donate to the site — we work hard for you.

How to sort a map by value

Short answer

Sort the entrySet() pairs with Map.Entry.comparingByValue() and collect them into a LinkedHashMap, which keeps the order:

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);
}

Output:

{Boris=67, Anna=82, Oleg=95}

Descending order

Pass a reverse comparator to 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()));
}

Output:

Oleg 95
Anna 82
Boris 67

Top N

Add limit() to get the top few:

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);
}

Output:

[home, shop]

Common mistake

Collecting the sorted stream with a plain Collectors.toMap(). It creates a HashMap, and the order is lost again:

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);
}

Output:

{Boris=67, Oleg=95, Anna=82}

Always pass LinkedHashMap::new as the fourth argument.

Functions used in this recipe

Thanks for reading!

Donate to the site — we work hard for you.