Home > OS >  Why sorting a HashMap<T, T> requires converting and then sorting a List<Map.Entry<T, T&g
Why sorting a HashMap<T, T> requires converting and then sorting a List<Map.Entry<T, T&g

Time:01-06

I came across a problem of sorting a HashMap<String, Integer> based on values. But, I came across many articles over the internet which first created a linkedList/arraylist of Map.Entry<String, Integer> and then sorted it on the basis of value.

Below is the code snippet showing sorting of a hashmap on the basis of key.

// Java program to sort hashmap by values
import java.util.*;
import java.lang.*;
 
public class Main {
 
    // function to sort hashmap by values
    public static HashMap<String, Integer> sortByValue(HashMap<String, Integer> hm)
    {
        // Create a list from elements of HashMap
        List<Map.Entry<String, Integer> > list =
               new LinkedList<Map.Entry<String, Integer> >(hm.entrySet());
 
        // Sort the list
        Collections.sort(list, new Comparator<Map.Entry<String, Integer> >() {
            public int compare(Map.Entry<String, Integer> o1,
                               Map.Entry<String, Integer> o2)
            {
                return (o1.getValue()).compareTo(o2.getValue());
            }
        });
         
        // put data from sorted list to hashmap
        HashMap<String, Integer> temp = new LinkedHashMap<String, Integer>();
        for (Map.Entry<String, Integer> aa : list) {
            temp.put(aa.getKey(), aa.getValue());
        }
        return temp;
    }
 
    // Driver Code
    public static void main(String[] args)
    {
 
        HashMap<String, Integer> hm = new HashMap<String, Integer>();
 
        // enter data into hashmap
        hm.put("Math", 98);
        hm.put("Data Structure", 85);
        hm.put("Database", 91);
        hm.put("Java", 95);
        hm.put("Operating System", 79);
        hm.put("Networking", 80);
        Map<String, Integer> hm1 = sortByValue(hm);
 
        // print the sorted hashmap
        for (Map.Entry<String, Integer> en : hm1.entrySet()) {
            System.out.println("Key = "   en.getKey()  
                          ", Value = "   en.getValue());
        }
    }
}

My question is, why is there a need to convert hashmap to list of entrySet and then sort it?

According to my understanding, we should be able to directly sort it based on the values just like any POJO class on a certain parameter. There shouldn't be any need to convert it into some collection and then sort it.

CodePudding user response:

Instead of placing the values in a map and sorting, create a record or class to hold the data. After populating with instances of the class, sort the list prior to placing in the map. It is necessary to use a LinkedHashMap to preserve the sorted order. Otherwise, the normal behavior of a HashMap will most likely disturb the sort.

List<Rec> list = List.of(
        new Rec("Math", 98), new Rec("Data Structure", 85),
        new Rec("Database", 91), new Rec("Java", 95),
        new Rec("Operating System", 79), new Rec("Networking", 80));

Map<String, Integer> result = list.stream()
        .sorted(Comparator.comparing(Rec::getVal))
        .collect(Collectors.toMap(Rec::getName, Rec::getVal,
                (a, b) -> a, LinkedHashMap::new));

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

prints

Operating System=79
Networking=80
Data Structure=85
Database=91
Java=95
Math=98

The issue, imo, is that not just any map lends itself to be sorted on values. Sorting a regular HashMap after the fact on values would be fruitless since inserting the keys would still perturb the order. Sorting before wouldn't help. A TreeMap won't work since it is designed to sort on keys and any supplied Comparator sorts using a KeyExtractor. And I suspect that any Map that might allow this would still convert to another data structure to accomplish the sort and return some LinkedHashMap or equivalent.

  • Related