0

I am using map interface to read from a file and then store the values in that as a key value pair.

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

The value is

A 25
D 10
B 15
E 15
C 17

I want to first sort by value in descending order Sorting the Map<Key,Value> in descending order based on the value . This will help to achieve the order in descending order. But if the value are duplicate i want to sort by key in ascending order.

Expected Output

A 25
C 17
B 15
E 15
D 10

Does any one know how to achieve this .

Kotlin Learner
  • 3,995
  • 6
  • 47
  • 127

2 Answers2

1

You can use Comparator.comparing and thenComparing to sort in the correct order. Streams can be used to sort and collect the new Map to a LinkedHashMap to retain the new order.

Map<String, Integer> map = Map.of("A", 25, "D", 10, "B", 15, "E", 15, "C", 17);
Map<String, Integer> result = map.entrySet().stream()
    .sorted(Comparator.<Map.Entry<String, Integer>>comparingInt(Map.Entry::getValue)
       .reversed().thenComparing(Map.Entry::getKey))
    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, 
         (a,b)->b, LinkedHashMap::new));
System.out.println(result);

Demo

Unmitigated
  • 76,500
  • 11
  • 62
  • 80
  • can you explain me .`sorted(Comparator.>comparingInt(Map.Entry::getValue) .reversed().thenComparing(Map.Entry::getKey))` this part – Kotlin Learner Aug 08 '21 at 16:48
  • also this part `.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a,b)->b, LinkedHashMap::new))` – Kotlin Learner Aug 08 '21 at 16:48
  • @vivekmodi `Comparator.comparingInt` is used here to sort by the value of each entry, and we call `reversed` to get descending order (ascending is the default). `thenComparing` is used to sort the keys in ascending order in case the values are the same. `Collectors.toMap` here just converts the stream of entries to a `LinkedHashMap`. See the documentation for more details. – Unmitigated Aug 08 '21 at 16:53
1

As an alternative to the accepted answer, I would extract the comparators which IMO makes it more readable, i.e to something like:

Map<String, Integer> map = Map.of("A", 25, "D", 10, "B", 15, "E", 15, "C", 17);

Comparator<Map.Entry<String,Integer>> byValueDesc = Map.Entry.comparingByValue(Comparator.reverseOrder());
Comparator<Map.Entry<String,Integer>> byKeyAsc = Map.Entry.comparingByKey();

Map<String, Integer> result =

    map.entrySet()
            .stream()
            .sorted(byValueDesc.thenComparing(byKeyAsc))
            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1,e2)->e1, LinkedHashMap::new));
Eritrean
  • 15,851
  • 3
  • 22
  • 28