I am trying to implement a custom comparator that sorts a list of objects in descending order, but while doing so, it ignores when the object has a specific value (-1 in my case). Thus, the objects with that value retain their original position, but all the objects around them will be sorted in descending order. For example, if the list is :
Candidate candidate1 = new Candidate("id1", 0.4);
Candidate candidate2 = new Candidate("id2", -1.0);
Candidate candidate3 = new Candidate("id3", 0.8);
List<Candidate> inputCandidates = ImmutableList.of(candidate1, candidate2, candidate3)
The resulting order should be
[
Candidate(super=Candidate(id=id3), value=0.8),
Candidate(super=Candidate(id=id2), value=-1.0),
Candidate(super=Candidate(id=id1), value=0.4)
]
Currently, I am trying something like this:
public final Comparator<Candidate> customComparator() {
return (Candidate one, Candidate two) -> {
double scoreOne = one.getValue() != null ? one.getValue() : 0d;
double scoreTwo = two.getValue() != null ? two.getValue() : 0d;
if (scoreOne == scoreTwo) return 0;
if (scoreOne == -1.0d) return 1;
if (scoreTwo == -1.0d) return -1;
return Double.compare(scoreTwo, scoreOne);
};
}
However, this instead gives me:
[
Candidate(super=Candidate(id=id3), value=0.8),
Candidate(super=Candidate(id=id1), value=0.4),
Candidate(super=Candidate(id=id2), value=-1.0)
]
Could someone please help me figure out where I am going wrong?
>Solution :
There is no solution using a single Comparator (or at least I failed to find it so). Here is a working solution requiring two steps:
-
Sort all the values in the descending (
reversed()) order without the specific value and collect it as a mutable list:List<Candidate> sorted = inputCandidates.stream() .filter(candidate -> candidate.getValue() != -1.0) .sorted(Comparator.comparing(Candidate::getValue).reversed()) .collect(Collectors.toCollection(ArrayList::new)); -
Iterate through the former collection and add the candidates with the specific value (
-1.0) to its original index position in the newly sorted list:for (int i=0; i<inputCandidates.size(); i++) { Candidate candidate = inputCandidates.get(i); if (candidate.getValue() == -1.0) { sorted.add(i, candidate); } }
Example input:
Candidate candidate1 = new Candidate("id1", 0.4); Candidate candidate2 = new Candidate("id2", -1.0); // fixed position Candidate candidate3 = new Candidate("id3", -1.0); // fixed position Candidate candidate4 = new Candidate("id4", 0.8); Candidate candidate5 = new Candidate("id5", -1.0); // fixed position Candidate candidate6 = new Candidate("id6", 0.5);
Example output:
sorted.forEach(c -> System.out.println(c.getId() + " : " + c.getValue()));
id4 : 0.8 id2 : -1.0 // fixed position id3 : -1.0 // fixed position id6 : 0.5 id5 : -1.0 // fixed position id1 : 0.4