Sort Map by values in Java
This post will discuss various methods to sort a map by values in Java, i.e., sort the map according to the natural ordering of its values.
1. Using TreeMap
TreeMap is a Red-Black tree-based implementation of Map, which is sorted according to comparator passed to its constructor. By writing a custom comparator to the TreeMap, we can sort the map according to the natural ordering of its values, as shown below:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
import java.util.*; // Custom Comparator to sort the map according to the natural ordering of its values class CustomComparator<K,V extends Comparable> implements Comparator<K> { private Map<K, V> map; public CustomComparator(Map<K, V> map) { this.map = new HashMap<>(map); } @Override public int compare(K s1, K s2) { return map.get(s1).compareTo(map.get(s2)); } } class Main { // Generic method to sort map by values using `TreeMap` public static <K, V> Map<K, V> sortByValues(Map<K, V> map) { Comparator<K> comparator = new CustomComparator(map); Map<K, V> sortedMap = new TreeMap<>(comparator); sortedMap.putAll(map); return sortedMap; } public static void main(String[] args) { Map<String, String> country = new HashMap<>(); country.put("India", "New Delhi"); country.put("USA", "Washington D.C."); country.put("Japan", "Tokyo"); country.put("China", "Beijing"); country = sortByValues(country); System.out.println("Sorted map by values: " + country); } } |
Output:
Sorted map by values :
{China=Beijing, India=New Delhi, Japan=Tokyo, USA=Washington D.C.}
Using Guava’s TreeMap:
Google’s Guava library also provides TreeMap implementation, which we can use to create a mutable, empty TreeMap instance, which is sorted according to a Comparator passed to its constructor.
|
1 2 3 4 5 6 7 8 9 10 |
// Generic method to sort map by values using Guava's `TreeMap` public static <K, V> TreeMap<K, V> sortByValues(Map<K, V> unsortedMap) { Comparator<K> comparator = new CustomComparator(unsortedMap); TreeMap<K, V> sortedMap = Maps.newTreeMap(comparator); sortedMap.putAll(unsortedMap); return sortedMap; } |
2. Using LinkedHashMap
LinkedHashMap is a hash table and linked list implementation of the Map interface, with predictable iteration order, which is the order in which values were inserted into the map. We can use this property to produce a copy of a map that is sorted according to the natural ordering of its values.
- Create a list of map entries and sort them based on their values.
- Create an empty
LinkedHashMapand for every map entry in the sorted list, insert key-value pair in it.
The resultant LinkedHashMap will be sorted by values.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
import java.util.*; class Main { // Generic method to sort map by values using `LinkedHashMap` public static <K,V extends Comparable> Map<K, V> sortByValues(Map<K, V> map) { // create a list of map entries and sort them based on their values List<Map.Entry<K, V>> mappings = new ArrayList<>(map.entrySet()); Collections.sort(mappings, Comparator.comparing(Map.Entry::getValue)); // create an empty insertion-ordered `LinkedHashMap` Map<K, V> linkedHashMap = new LinkedHashMap<>(); // for every map entry in the sorted list, insert key-value pair in `LinkedHashMap` for (Map.Entry<K, V> entry: mappings) { linkedHashMap.put(entry.getKey(), entry.getValue()); } return linkedHashMap; } public static void main(String[] args) { Map<String, String> country = new HashMap<>(); country.put("India", "New Delhi"); country.put("USA", "Washington D.C."); country.put("Japan", "Tokyo"); country.put("China", "Beijing"); country = sortByValues(country); System.out.println("Sorted map by values: " + country); } } |
Output:
Sorted map by values :
{China=Beijing, India=New Delhi, Japan=Tokyo, USA=Washington D.C.}
3. Using Java 8
We can also use Java 8 Stream to sort map by values. Following are the steps:
- Obtain stream from the set view of the mappings contained in the map.
- Sort the stream in natural order of values using
Stream.sorted()method by passing comparator returned byMap.Entry.comparingByValue(). - Collect all sorted elements in a
LinkedHashMapusingStream.collect()withCollectors.toMap().
Please note that a stream is a sequence of items, not a sequence of key/value pairs. So, we can’t construct a map out of a stream without specifying how to extract values and values from it. Java 8 provides Collectors.toMap() method for this purpose. We need to use an overloaded version of toMap() that returns LinkedHashMap instead of HashMap to retain the sorted order.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.stream.Collectors; class Main { public static void main(String[] args) { Map<String, String> country = new HashMap<>(); country.put("India", "New Delhi"); country.put("USA", "Washington D.C."); country.put("Japan", "Tokyo"); country.put("China", "Beijing"); // Sort map by values using Java 8 Stream country = country.entrySet() .stream() .sorted(Map.Entry.comparingByValue()) .collect(Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, (oldValue, newValue) -> oldValue, LinkedHashMap::new )); System.out.println("Sorted map by values: " + country); } } |
Output:
Sorted map by values :
{China=Beijing, India=New Delhi, Japan=Tokyo, USA=Washington D.C.}
Following is another approach that doesn’t use Java 8 collectors. It uses the Stream.forEachOrdered() method on the sorted stream that inserts each element of the stream into a new LinkedHashMap.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.stream.Collectors; class Main { public static void main(String[] args) { Map<String, String> country = new HashMap<>(); country.put("India", "New Delhi"); country.put("USA", "Washington D.C."); country.put("Japan", "Tokyo"); country.put("China", "Beijing"); // Sort map by values using Java 8 Stream Map<String, String> sortedMap = new LinkedHashMap<>(); country.entrySet() .stream() .sorted(Map.Entry.comparingByValue()) .forEachOrdered(entry -> sortedMap.put(entry.getKey(), entry.getValue())); System.out.println("Sorted map by values: " + country); } } |
Output:
Sorted map by values :
{China=Beijing, India=New Delhi, Japan=Tokyo, USA=Washington D.C.}
That’s all about sorting Map by values in Java.
Related Post:
Exercise: Modify above code to sort map by reverse ordering of its values
References:
1. TreeMap Javadoc – Java SE 8
2. LinkedHashMap Javadoc – Java SE 8 Javadoc
Thanks for reading.
To share your code in the comments, please use our online compiler that supports C, C++, Java, Python, JavaScript, C#, PHP, and many more popular programming languages.
Like us? Refer us to your friends and support our growth. Happy coding :)