As per my knowledge, Comparator.comparingInt()
should sort in ascending order and Comparator.comparingInt().reversed
should sort in descending order. But I found a scenario where this is inverse.
This is better explained with an example. Following is my code.
Amount class:
class Amount
{
int lineNum;
int startIndex;
Double value;
//Getters , setters and toString.
}
Main method:
public static void main( String[] args )
{
List<Amount> amounts = new ArrayList<>();
amounts.add( new Amount( 1.0, 5, 10 ) ); //LINE_NUM 5
amounts.add( new Amount( 3.0, 9, 30 ) );
amounts.add( new Amount( 2.0, 3, 40 ) );
amounts.add( new Amount( 9.0, 5, 20 ) ); //LINE_NUM 5
amounts.add( new Amount( 6.0, 1, 50 ) );
amounts.add( new Amount( 4.0, 5, 20 ) ); //LINE_NUM 5
System.out.println( ".............BEFORE SORTING.........." );
amounts.forEach( System.out::println );
amounts.sort(
Comparator.comparingInt( Amount::getLineNum ) //NOTE THIS
. .thenComparingInt( Amount::getStartIndex ).reversed()
.thenComparingDouble( Amount::getValue ) );
System.out.println( "\n\n.............AFTER SORTING.........." );
amounts.forEach( System.out::println );
}
I wanted amount list sorted by lineNum ascending, by startIndex descending and value ascending.
So my expectation was this.
.............AFTER SORTING..........(EXPECTATION)
Amount [lineNum=1, startIndex=50, value=6.0]
Amount [lineNum=3, startIndex=40, value=2.0]
Amount [lineNum=5, startIndex=20, value=4.0]
Amount [lineNum=5, startIndex=20, value=9.0]
Amount [lineNum=5, startIndex=10, value=1.0]
Amount [lineNum=9, startIndex=30, value=3.0]
.............AFTER SORTING..........(ACTUAL)
Amount [lineNum=9, startIndex=30, value=3.0]
Amount [lineNum=5, startIndex=20, value=4.0]
Amount [lineNum=5, startIndex=20, value=9.0]
Amount [lineNum=5, startIndex=10, value=1.0]
Amount [lineNum=3, startIndex=40, value=2.0]
Amount [lineNum=1, startIndex=50, value=6.0]
Everything was right except for lineNum order. Amounts were sorted by lineNumber descending while I was expecting it to be in ascending order.
The results were as expected when I changed the Comparator to following
amounts.sort(
Comparator.
comparingInt( Amount::getLineNum ).reversed()
.thenComparingInt( Amount::getStartIndex ).reversed()
.thenComparingDouble( Amount::getValue ) );
Which is strange because, comparingInt( Amount::getLineNum ).reversed()
was supposed to sort amounts by line number descending .
One more thing I noticed is, Comparing by StartIndex works as expected. But Comparing by lineNumber part is not.
Can somebody explain this?
You can use Comparator. reverseOrder() to have a comparator giving the reverse of the natural ordering. If you want to reverse the ordering of an existing comparator, you can use Comparator. reversed() .
Comparator , represents a component that can compare two objects so they can be sorted using sorting functionality in Java. When sorting e.g a Java List you can pass a Java Comparator to the sorting method. The Comparator is then used to compare the objects in the List during sorting.
It's easier to understand what's going on if you put each call on a line:
Comparator.comparingInt(Amount::getLineNum)
.thenComparingInt(Amount::getStartIndex)
.reversed()
.thenComparingDouble(Amount::getValue)
That reversed()
returns a comparator which reverses the results of the comparator it's called on... which is "the comparator which first compares the line number, then the start index." It's not like it's "bracketed" to just the scope of the previous thenComparingInt()
call, which is how your previous formatting made it look like.
You could do it as:
Comparator.comparingInt(Amount::getLineNum)
.thenComparing(Comparator.comparingInt(Amount::getStartIndex).reversed())
.thenComparingDouble(Amount::getValue)
At that point it's only the start index comparison that's reversed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With