比较器 .comparing().reversed() 奇怪的行为/没有按预期工作
Comparator .comparing().reversed() strange behaviour / not working as expected
据我所知,Comparator.comparingInt()
应按升序排序,Comparator.comparingInt().reversed
应按降序排序。但我发现这是相反的情况。
最好用一个例子来解释。以下是我的代码。
金额class:
class Amount
{
int lineNum;
int startIndex;
Double value;
//Getters , setters and toString.
}
主要方法:
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 );
}
我想要按 lineNum 升序、startIndex 降序和值升序排序的金额列表。
所以我的期望是这样。
.............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]
除 lineNum order 外,一切正常。金额按行号 降序 排序,而我希望它按 升序 .
当我将 Comparator 更改为 following
时,结果符合预期
amounts.sort(
Comparator.
comparingInt( Amount::getLineNum ).reversed()
.thenComparingInt( Amount::getStartIndex ).reversed()
.thenComparingDouble( Amount::getValue ) );
这很奇怪,因为 comparingInt( Amount::getLineNum ).reversed()
应该按行号降序对金额进行排序。
我注意到的另一件事是,比较 StartIndex 按预期工作。但是 比较 lineNumber 部分不是。
有人可以解释一下吗?
如果将每个调用都放在一条线上,则更容易理解发生了什么:
Comparator.comparingInt(Amount::getLineNum)
.thenComparingInt(Amount::getStartIndex)
.reversed()
.thenComparingDouble(Amount::getValue)
那个 reversed()
returns 一个比较器,它反转调用它的比较器的结果...这是 "the comparator which first compares the line number, then the start index." 它不像 "bracketed" 只是之前 thenComparingInt()
调用的范围,这是您之前的格式设置的样子。
您可以这样做:
Comparator.comparingInt(Amount::getLineNum)
.thenComparing(Comparator.comparingInt(Amount::getStartIndex).reversed())
.thenComparingDouble(Amount::getValue)
在那个点,只有起始索引比较被颠倒了。
来自 docs:
reversed()
: Returns a comparator that imposes the reverse ordering of this comparator.
thenComparing()
: Returns a lexicographic-order comparator with another comparator. If this Comparator considers two elements equal, i.e. compare(a, b) == 0, other is used to determine the order.
每一步都会在前一步的基础上创建一个新的比较器。所以 reversed()
方法创建了一个 reversed comparator of
Comparator.comparingInt(Amount::getLineNum).thenComparingInt(Amount::getStartIndex)
要仅反转第二个,您应该将其包装在自己的比较器中:
.thenComparing(Comparator.comparingInt(Amount::getStartIndex).reversed())
在你的第二个解决方案中,结果是正确的,因为你实际上将第一个条件颠倒了两次:
Comparator.comparingInt(Amount::getLineNum).reversed() // reverses one time
.thenComparingInt(Amount::getStartIndex).reversed() // reverses all before (also the first one)
所以完整的解决方案如下所示:
Comparator.comparingInt(Amount::getLineNum)
.thenComparing(Comparator.comparingInt(Amount::getStartIndex).reversed())
.thenComparingDouble(Amount::getValue)
将 reversed() 的调用放在 thenComparing 中:
Comparator.comparingInt(Amount::getLineNum)
.thenComparing(Comparator.comparingInt(Amount::getStartIndex).reversed())
.thenComparingDouble( Amount::getValue );
据我所知,Comparator.comparingInt()
应按升序排序,Comparator.comparingInt().reversed
应按降序排序。但我发现这是相反的情况。
最好用一个例子来解释。以下是我的代码。
金额class:
class Amount
{
int lineNum;
int startIndex;
Double value;
//Getters , setters and toString.
}
主要方法:
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 );
}
我想要按 lineNum 升序、startIndex 降序和值升序排序的金额列表。
所以我的期望是这样。
.............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]
除 lineNum order 外,一切正常。金额按行号 降序 排序,而我希望它按 升序 .
当我将 Comparator 更改为 following
时,结果符合预期amounts.sort(
Comparator.
comparingInt( Amount::getLineNum ).reversed()
.thenComparingInt( Amount::getStartIndex ).reversed()
.thenComparingDouble( Amount::getValue ) );
这很奇怪,因为 comparingInt( Amount::getLineNum ).reversed()
应该按行号降序对金额进行排序。
我注意到的另一件事是,比较 StartIndex 按预期工作。但是 比较 lineNumber 部分不是。
有人可以解释一下吗?
如果将每个调用都放在一条线上,则更容易理解发生了什么:
Comparator.comparingInt(Amount::getLineNum)
.thenComparingInt(Amount::getStartIndex)
.reversed()
.thenComparingDouble(Amount::getValue)
那个 reversed()
returns 一个比较器,它反转调用它的比较器的结果...这是 "the comparator which first compares the line number, then the start index." 它不像 "bracketed" 只是之前 thenComparingInt()
调用的范围,这是您之前的格式设置的样子。
您可以这样做:
Comparator.comparingInt(Amount::getLineNum)
.thenComparing(Comparator.comparingInt(Amount::getStartIndex).reversed())
.thenComparingDouble(Amount::getValue)
在那个点,只有起始索引比较被颠倒了。
来自 docs:
reversed()
: Returns a comparator that imposes the reverse ordering of this comparator.
thenComparing()
: Returns a lexicographic-order comparator with another comparator. If this Comparator considers two elements equal, i.e. compare(a, b) == 0, other is used to determine the order.
每一步都会在前一步的基础上创建一个新的比较器。所以 reversed()
方法创建了一个 reversed comparator of
Comparator.comparingInt(Amount::getLineNum).thenComparingInt(Amount::getStartIndex)
要仅反转第二个,您应该将其包装在自己的比较器中:
.thenComparing(Comparator.comparingInt(Amount::getStartIndex).reversed())
在你的第二个解决方案中,结果是正确的,因为你实际上将第一个条件颠倒了两次:
Comparator.comparingInt(Amount::getLineNum).reversed() // reverses one time
.thenComparingInt(Amount::getStartIndex).reversed() // reverses all before (also the first one)
所以完整的解决方案如下所示:
Comparator.comparingInt(Amount::getLineNum)
.thenComparing(Comparator.comparingInt(Amount::getStartIndex).reversed())
.thenComparingDouble(Amount::getValue)
将 reversed() 的调用放在 thenComparing 中:
Comparator.comparingInt(Amount::getLineNum)
.thenComparing(Comparator.comparingInt(Amount::getStartIndex).reversed())
.thenComparingDouble( Amount::getValue );