1. Introduction
HashMaps are incredibly useful data structures in Java programming for efficiently retrieving and storing key-value pairs. However, it’s common to encounter situations where we must sort these pairs based on their keys or values. This article will explore various techniques to sort a HashMap in Java.
First, we’ll discuss different approaches, such as utilizing TreeMap, ArrayList with Collections.sort(), and TreeSet, to sort our HashMap by keys. Then, we’ll delve into sorting HashMap values, covering methods like using Java’s Stream API and the Guava library. Throughout the article, we’ll provide code examples to demonstrate each technique, making implementing these sorting methods in your Java projects easier.
2. What is HashMap, and How to Sort a HashMap in Java?
2.1. Basics of HashMap
HashMap is a class in Java that implements the Map interface. It stores key-value pairs in a hash table, where each key is mapped to a corresponding value. The keys in a HashMap must be unique, but duplicate values are allowed.
HashMap is a powerful data structure in Java, part of the java.util package that can implement dictionaries, directories, and look-up tables. It stores data in key-value pairs, allowing you to easily retrieve a value by providing its corresponding key. Key and value types, such as String or Integer, can differ.
HashMap<String, Integer> hashMapExample = new HashMap<>();
HashMaps are unordered by nature and not specifically designed for sorting. To sort HashMap entries by key or value, there are several approaches to choose from.
2.2. Sorting by Keys
To sort a HashMap by its keys, use the TreeMap class. Keys in TreeMap are arranged according to their natural arrangement. It will produce a new TreeMap with identical elements from the source HashMap but ordered by their keys by utilising the TreeMap constructor that accepts a Map as its input.
Here’s an example:
HashMap<String, Integer> myHashMap = new HashMap<String, Integer>(); // ... add entries to myHashMap ... TreeMap<String, Integer> sortedByKeys = new TreeMap<>(myHashMap); // Now sortedByKeys contains a sorted value of myHashMap by keys.
2.3. Sorting by Value
Since there is no direct method for sorting a HashMap by values, the process is a little more difficult. The method entails building a unique Comparator that contrasts the elements according to their values. Transform the HashMap’s entry set into a List, then use the Collections.sort() function to order the List using the unique Comparator.
Here’s an example:
HashMap<String, Integer> myHashMap = new HashMap<String, Integer>(); // ... add entries to myHashMap ... // Custom comparator to sort by values Comparator<Map.Entry<String, Integer>> valueComparator = (entry1, entry2) -> entry1.getValue().compareTo(entry2.getValue()); // Convert entry set to a list and sort List<Map.Entry<String, Integer>> sortedList = new ArrayList<>(myHashMap.entrySet()); Collections.sort(sortedList, valueComparator);
Now, sortedList contains the entries of the HashMap, sorted by their values.
3. Sorting HashMap in Java
3.1. Using TreeMap
A Red-Black Tree, which enables items to be kept in sorted order, is implemented via a data structure called a TreeMap. Create a TreeMap and send the HashMap to the constructor when you wish to sort a HashMap by its keys. The sorted values are automatic, depending on their keys.
Map<String, Integer> hashMap = new HashMap<>(); // add elements to hashMap Map<String, Integer> sortedMap = new TreeMap<>(hashMap);
3.2. Using ArrayList and Collections.sort()
Using an ArrayList to hold the items of the HashMap and sorting the ArrayList using Collections.sort() is another method for sorting a HashMap. This approach enables us to sort the elements by key or value depending on our comparator.
// Sort by keys List<Map.Entry<String, Integer>> list = new ArrayList<>(hashMap.entrySet()); Collections.sort(list, Map.Entry.comparingByKey()); // Sort by HashMap values Collections.sort(list, Map.Entry.comparingByValue());
3.3. Using TreeSet
TreeSet is a sorted set implementation that maintains elements in their natural order (or using a specified comparator). To sort a HashMap using TreeSet, we can obtain the keySet or the entrySet and then pass it to the TreeSet’s constructor.
// Sort by keys SortedSet<String> sortedKeys = new TreeSet<>(hashMap.keySet()); // Iterate over the sorted keys for (String key : sortedKeys) { Integer value = hashMap.get(key); // Do something }
3.4. Using LinkedHashMap
LinkedHashMap is a HashMap subclass that maintains a doubly-linked list of its entries, allowing iteration order to be maintained. To sort a HashMap using a LinkedHashMap, we can first sort its entries using an ArrayList and then insert the sorted entries into a LinkedHashMap.
// Sort the entries by key or value as shown in the ArrayList section List<Map.Entry<String, Integer>> list = new ArrayList<>(hashMap.entrySet()); Collections.sort(list, Map.Entry.comparingByKey()); // Create a LinkedHashMap and insert the sorted entries Map<String, Integer> sortedMap = new LinkedHashMap<>(); for (Map.Entry<String, Integer> entry : list) { sortedMap.put(entry.getKey(), entry.getValue()); }
3.5. Using Stream API
Streams API in Java can sort a HashMap by converting it into a Stream of Map.Entry objects and then sort the stream based on the keys or values of the map.
private static Map<Integer, String> map = new HashMap<>(); static { map.put(1, "One"); map.put(3, "Three"); map.put(4, "Four"); map.put(2, "Two"); }
3.5.1. Sort By Key Ascending
private static void streamsSortAscendingByKey() { Map<Integer, String> sorted = map.entrySet().stream() .sorted(Map.Entry.comparingByKey()) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new)); sorted.forEach((k, v) -> System.out.println(k + " " + v)); }
We are using the streams sorted() method to compare by keys which are then collected into LinkedHashMap that can keep the insertion order. Hence why the map is sorted according to stream conditions.
3.5.2. Sort By Key Descending
private static void streamsSortDescendingByKey() { Map<Integer, String> sorted = map.entrySet().stream() .sorted(Map.Entry.<Integer, String>comparingByKey().reversed()) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new)); sorted.forEach((k, v) -> System.out.println(k + " " + v)); }
Similarly, if we want to sort by key but descendingly, we need to add Comparator reversed() method. Specifying the compiler’s type is essential so it knows the generic type.
3.5.3. Sort By Value
private static void streamsSortAscendingByValue() { Map<Integer, String> sorted = map.entrySet().stream() .sorted(Map.Entry.comparingByValue()) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new)); sorted.forEach((k, v) -> System.out.println(k + " " + v)); }
Sorting by value is very similar, but in our sorted() method, we need to pass comparingByValue() instead. A custom Comparator can be passed into the method if custom sorting is required.
4. Comparator and Comparable Interfaces
In Java, we often use the Comparator and Comparable interfaces to sort elements in a collection, such as a HashMap. These two interfaces allow us to define custom sorting logic and implement natural ordering in our code.
Natural order refers to the default sorting order inherent to the elements. For instance, numerical values are sorted in ascending order, while strings are sorted alphabetically. Java’s built-in classes, such as Integer and String, already implemented the Comparable interface, allowing us to easily sort collections containing these data types.
Here’s a simple example of how we can use Java’s predefined natural ordering:
List<Integer> numbers = Arrays.asList(5, 3, 8, 1); Collections.sort(numbers); // [1, 3, 5, 8]
4.1. Custom Object Sorting
However, we may need to define our custom sorting logic when dealing with custom objects or more complex scenarios. This is where both the Comparator and Comparable interfaces come into play.
The objects should implement the Comparable interface, providing a default sorting order. We need to override the compareTo() method and define the logic for comparing objects with each other.
Consider a simple Person class:
public class Person implements Comparable<Person> { private String name; private int age; // Getters, setters, and constructors... @Override public int compareTo(Person other) { return this.name.compareTo(other.name); } }
With the Comparable interface implemented, we can now sort a list of Person objects alphabetically by their names:
List<Person> people = // Populate list... Collections.sort(people);
On the other hand, the Comparator interface is intended for external classes that define custom sorting logic. This is useful when sorting a collection using different criteria without modifying the original class. Let’s create a separate comparator for sorting Person objects by age:
public class AgeComparator implements Comparator<Person> { @Override public int compare(Person person1, Person person2) { return Integer.compare(person1.getAge(), person2.getAge()); } }
Now we can use the AgeComparator to sort our list based on the age of the Person objects:
List<Person> people = // Populate list... Collections.sort(people, new AgeComparator());
5. Google Guava
Guava is a popular and robust open-source library that can sort HashMaps. It contains many utility classes for easing our life as developers. We can use its Ordering class to sort the HashMap:
private static void sortUsingGuava() { Ordering<Integer> ascending = Ordering .natural() .onResultOf(Functions.forMap(map, 0)); ImmutableSortedMap<Integer, String> sorted = ImmutableSortedMap.copyOf(map, ascending); sorted.forEach((k, v) -> System.out.println(k + " " + v));
6. Advanced Sorting Techniques
One way to sort a HashMap by its values is to use the putAll method in combination with the comparingByValue comparator. We can achieve this by creating a new LinkedHashMap, which stores entries in the order they were inserted and then populates them with the sorted entries from the original HashMap.
Here’s a code example:
import java.util.*; import java.util.stream.Collectors; public class HashMapSorting { public static void main(String[] args) { HashMap<Integer, String> unsortedMap = new HashMap<>(); unsortedMap.put(3, "Three"); unsortedMap.put(1, "One"); unsortedMap.put(2, "Two"); LinkedHashMap<Integer, String> sortedMap = unsortedMap .entrySet() .stream() .sorted(Map.Entry.comparingByValue()) .collect(Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, (oldValue, newValue) -> oldValue, LinkedHashMap::new )); System.out.println(sortedMap); } }
6.1. Using Collectors.toMap and Map Interface
Another approach to sorting a HashMap is using the Collectors.toMap method alongside the Map interface, either by key or value. This can be achieved using Java’s Stream API. Here’s an example showing how to sort a HashMap by key:
import java.util.*; import java.util.stream.Collectors; public class HashMapSorting { public static void main(String[] args) { HashMap<Integer, String> unsortedMap = new HashMap<>(); unsortedMap.put(3, "Three"); unsortedMap.put(1, "One"); unsortedMap.put(2, "Two"); Map<Integer, String> sortedMap = unsortedMap.entrySet().stream() .sorted(Map.Entry.comparingByKey()) .collect(Collectors.toMap( Map.Entry::getKey, Map.Entry::getValue, (oldValue, newValue) -> oldValue, LinkedHashMap::new )); System.out.println(sortedMap); } }
7. Summary
This article looked at how to sort a HashMap in Java. It’s a pretty easy thing to do if you know the secrets! Sorting can be done using TreeMap, ArrayList and Collections.sort(), TreeSet, LinkedHashMap, and other techniques. The Comparator and Comparable interfaces provide a way to customize the sorting order and implement custom object sorting.
Overall, sorting HashMaps in Java is a flexible and powerful tool that can be used to organize and manipulate data efficiently.
Daniel Barczak
Daniel Barczak is a software developer with a solid 9-year track record in the industry. Outside the office, Daniel is passionate about home automation. He dedicates his free time to tinkering with the latest smart home technologies and engaging in DIY projects that enhance and automate the functionality of living spaces, reflecting his enthusiasm and passion for smart home solutions.
Leave a Reply