Haris
Haris

Reputation: 135

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());

Upvotes: 10

Views: 11187

Answers (2)

Anonymous
Anonymous

Reputation: 86276

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().

Upvotes: 6

Naman
Naman

Reputation: 31878

You are looking for a custom Comparator such as this:

.sorted((o1, o2) -> o2.getValue().compareTo(o1.getValue()) == 0 ?
        o1.getKey().compareTo(o2.getKey()) : o2.getValue().compareTo(o1.getValue()))

Theoretically,

  • compare the values first in descending order o2.getValue().compareTo(o1.getValue()) and

  • if they are equal compare the keys in the ascending order o1.getKey().compareTo(o2.getKey()).

Upvotes: 8

Related Questions