Search code examples
javahashmappriority-queuecustom-sort

Custom sort for HashMap on Priority Queue


I want to get the sorted key value pair on value, and if the values are equal, I wanna sort on keys asc.

I tried using PriorityQueue like following but I am getting null pointer for some reason. Please help me understand the issue and probably answer my query.

This is what I came up with, but unfortunately the output of the code is

PQ : [Hello, Yes]

Where as I was expecting

PQ : [No, Hello]

    public static void main(String[] args) {

        Map<String, Integer> map = new HashMap<>() {{
            put("Hello", 50);
            put("Yes", 50);
            put("No", 100);
        }};
        PriorityQueue<String> pq = new PriorityQueue<>((a, b) -> {
            if (map.get(a).equals(map.get(b))) return a.compareTo(b);
            else return Integer.compare(map.get(b), map.get(a));
        });
        verifyPQ(map, pq);
        System.out.println(pq);
    }

    private static void verifyPQ(Map<String, Integer> map, PriorityQueue<String> pq) {
        for (String key : map.keySet()) {
            pq.add(key);
            if (pq.size() > 2) {
                pq.poll();
            }
        }
}

Solution

  • Why don't you use comparator instead of unnecessarily complicating things with priority queues?

    If I have understood correctly, you want to sort by value in descending order and by key in ascending order.

    Map<String, Integer> map = new HashMap<>();
    map.put("Hello", 50);
    map.put("Yes", 50);
    map.put("No", 100);
    
    
    map.entrySet()
       .stream()
       .sorted(Comparator.comparing(Entry<String,Integer>::getValue).reversed()
                         .thenComparing(Entry::getKey))
       .forEach(System.out::println);
    

    If you only need the first two, just add a limit

    map.entrySet()
       .stream()
       .sorted(Comparator.comparing(Entry<String,Integer>::getValue).reversed()
                         .thenComparing(Entry::getKey))
       .limit(2)
       .forEach(System.out::println);