How to Sort a HashMap by Value in Java - Stack Abuse

How to Sort a HashMap by Value in Java

In this tutorial, we'll take a look at how to sort a HashMap by value in Java.

Let's go ahead and create a simple HashMap:

Map<String, Integer> unsortedMap = new HashMap();

unsortedMap.put("John", 21);
unsortedMap.put("Maria", 34);
unsortedMap.put("Mark", 31);
unsortedMap.put("Sydney", 24);

unsortedMap.entrySet().forEach(System.out::println);

We've got Strings as keys, and Integers as values. And we'd like to sort this map based on the values.

HashMaps don't guarantee to maintain the order of its elements in any case. The order can change through time, and they most definitely won't be printed back in the order of insertion:

John=21
Mark=31
Maria=34
Sydney=24

If you re-run this program, it'll keep this order, since HashMaps order their elements into bins, based on the hash value of the keys. When printing values from a HashMap, its contents are printed sequentially, so the results will stay the same if we re-run the program multiple times.

Note: TreeMap extends the SortedMap interface, unlike the HashMap implementation. TreeMaps are meant to be the sorted counterpart, however, TreeMaps only sort by keys, given a comparator.

Sort HashMap by Value with LinkedHashMap

LinkedHashMap preserves the order of insertion. It keeps a doubly-linked list of all entries, allowing you to very naturally access and iterate over its elements.

So, the easiest way to convert an unsorted HashMap into a LinkedHashMap is to add the elements in the order we'd like them to be in.

Sort HashMap in Ascending Order

To sort the unsortedMap we've seen earlier, we'll create a new LinkedHashMap to house the elements in the order we want them to be in.

Let's start off with sorting a HashMap in ascending order:

Map<String, Integer> sortedMap = unsortedMap.entrySet().stream()
        .sorted(Comparator.comparingInt(e -> e.getValue()))
        .collect(Collectors.toMap(
                Map.Entry::getKey,
                Map.Entry::getValue,
                (a, b) -> { throw new AssertionError(); },
                LinkedHashMap::new
        ));

sortedMap.entrySet().forEach(System.out::println);

What we've done here is streamed the unsortedMap's set of Map.Entry objects. Then, using the sorted() method, we can use various Comparators to specify how the entries are compared.

Since we're dealing with simple integers, we can easily use Comparator.comparingInt() method, and pass in a Lambda Expression. Through this expression, we supply the sort key from type T (in our case, Integer).This method then returns a Comparator that compares that sort key.

Once they're sorted, we can collect() them into a new map, via the Collectors.toMap() call, where we use the same Map.Entry::getKey and Map.Entry::getValue as in the unsortedMap.

Finally, a new LinkedHashMap is instantiated, into which all of these elements, in sorted order, are inserted.

Running this code results in:

John=21
Sydney=24
Mark=31
Maria=34

Alternatively, instead of Comparator.comparingInt(), you can use Map.Entry.comparingByValue():

Map<String, Integer> sortedMap = unsortedMap.entrySet().stream()
        .sorted(Map.Entry.comparingByValue())
        .collect(Collectors.toMap(
                Map.Entry::getKey,
                Map.Entry::getValue,
                (a, b) -> { throw new AssertionError(); },
                LinkedHashMap::new
        ));

sortedMap.entrySet().forEach(System.out::println);

However, with this approach, you can't specify your own logic for the comparisons. Comparable values, like Integers, are sorted with the under-the-hood implementation. You could specify a custom object and specify your own comparison logic in that class, though.

In a very similar vein to this, you can also simply use the Map.Entry::getValue as well:

Map<String, Integer> sortedMap = unsortedMap.entrySet().stream()
        .sorted(Comparator.comparingInt(Map.Entry::getValue))
        .collect(Collectors.toMap(
                Map.Entry::getKey,
                Map.Entry::getValue,
                (a, b) -> { throw new AssertionError(); },
                LinkedHashMap::new
        ));

sortedMap.entrySet().forEach(System.out::println);

This also returns:

John=21
Sydney=24
Mark=31
Maria=34

This one is functionally the exact same as the previous one, as Map.Entry.comparingByValue() uses the getValue() method to compare entries anyway.

Sort HashMap in Descending Order

Git Essentials

Check out this hands-on, practical guide to learning Git, with best-practices and industry-accepted standards. Stop Googling Git commands and actually learn it!

Now, let's sort the unsorted HashMap in descending order instead. The only difference you need to make is the Lambda Expression we've supplied to the Comparator.comparingInt() method - we'll just use -e.getValue() instead:

Map<String, Integer> sortedMap = unsortedMap.entrySet().stream()
        .sorted(Comparator.comparingInt(e -> -e.getValue()))
        .collect(Collectors.toMap(
                Map.Entry::getKey,
                Map.Entry::getValue,
                (a, b) -> { throw new AssertionError(); },
                LinkedHashMap::new
        ));

sortedMap.entrySet().forEach(System.out::println);

This results in:

Maria=34
Mark=31
Sydney=24
John=21

This is the added benefit of using this approach, instead of either Map.Entry.comparingByValue() or Map.Entry::getValue. You can easily switch between descending and ascending order.

Conclusion

In this tutorial, we've gone over how to sort a Java HashMap by Value. We've used Java 8 Streams with the LinkedHashMap class to achieve this functionality, both to sort by ascending and descending values.

Last Updated: February 2nd, 2021

Improve your dev skills!

Get tutorials, guides, and dev jobs in your inbox.

No spam ever. Unsubscribe at any time. Read our Privacy Policy.

Want a remote job?

    Prepping for an interview?

    • Improve your skills by solving one coding problem every day
    • Get the solutions the next morning via email
    • Practice on actual problems asked by top companies, like:
     
     
     

    © 2013-2021 Stack Abuse. All rights reserved.