Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to define custom sorted comparator in java 8 Stream to compare on the key and the value

I want to sort a map using Java 8 streams and return a list of its key.

Map signature is:

Map<Integer, Integer> ranks = new HashMap<Integer, Integer>();

and the data will be like [ 1=6, 5=13, 2=11 ]

There are two conditions on which I have to sort and return a list of keys.

  1. If all the values of the keys are different, then sort and return a list based values in descending order, e.g.

    input [1=6 , 5=13 , 2= 11 , 4 = 14 ]
    result [4,5,2,1]
    
  2. If two or more values of the key are having same rank, then return these similar in an ascending order, and the rest of the item is in descending order with respect to their values, e.g.

    input [2=6 , 5=13 , 1= 11 , 3=13 ,9 = 22 ] result [9,3,5,1,2]
    

Below is the code snippet which is working fine for condition 1, but not for condition 2.

List<Integer> ranksList = ranks.entrySet().stream()
    .sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
    .map(Map.Entry::getKey)
    .limit(k)
    .collect(Collectors.toList());
like image 625
Haris Avatar asked Oct 29 '19 17:10

Haris


1 Answers

Declare the Comparator using thenComparing for chaining.

Comparator<Map.Entry<Integer, Integer>> entryComparator
            = Map.Entry.<Integer, Integer>comparingByValue(Comparator.reverseOrder())
                                         .thenComparing(Map.Entry.comparingByKey());

Map<Integer,Integer> ranks = Map.of(2, 6, 5, 13, 1, 11, 3, 13, 9, 22);

List<Integer> ranksList= ranks.entrySet().stream()
            .sorted(entryComparator)
            .map(Map.Entry::getKey).limit(47)
            .collect(Collectors.toList());

System.out.println(ranksList);

Output is the desired:

[9, 3, 5, 1, 2]

The type specification <Integer, Integer> of comparingByValue is necessary for Java to infer the types for Map.Entry.comparingByKey().

like image 181
Ole V.V. Avatar answered Sep 21 '22 12:09

Ole V.V.