【发布时间】:2017-02-22 14:33:05
【问题描述】:
我在 Scala 中遇到了一些非常奇怪的排序行为(2.11.8 和 2.12.1),用于 Seq[(Long, Double)]。我可能误解了一些基本的东西。
给定一个没有 Double.NaN 值的序列,一切都按预期工作
Seq[(Long, Double)]((1L, 2.5D), (2L, 0D), (11L, 11D), (2L, 10D)).sortWith(_._2 > _._2)
output >>> Seq[(Long, Double)] = List((11,11.0), (2,10.0), (1,2.5), (2,0.0))
如果我在排序列中添加一个带有NaN 的元组,就会发生奇怪的事情
Seq[(Long, Double)]((1L, 2.5D), (2L, 0D), (3L, Double.NaN), (11L, 11D), (2L, 10D)).sortWith(_._2 > _._2)
output >>> Seq[(Long, Double)] = List((1,2.5), (2,0.0), (5,NaN), (11,11.0), (2,10.0))
所以看起来什么都没做
如果我交换前两个元素
Seq[(Long, Double)]((2L, 0D), (1L, 2.5D), (5L, Double.NaN), (11L, 11D), (2L, 10D)).sortWith(_._2 > _._2)
output >>> Seq[(Long, Double)] = List((11,11.0), (2,10.0), (1,2.5), (2,0.0), (5,NaN))
排序再次起作用??
Seq[Double] 也是如此
Seq[Double](2.5, 0, Double.NaN, 11, 10).sortWith(_ > _)
output >>> Seq[Double] = List(2.5, 0.0, NaN, 11.0, 10.0)
Seq[Double](0, 2.5, Double.NaN, 11, 10).sortWith(_ > _)
output >>> Seq[Double] = List(11.0, 10.0, 2.5, 0.0, NaN)
.sortBy(_._2) 似乎适用于所有情况。这是scala中的错误,还是我的大脑中的错误?我在 Ubuntu 16.04 和 Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_91 上使用 scala 2.11.8 和 2.12.1。
更新
事实证明,如果我颠倒排序顺序,那么会发生一些更可预测的事情
Seq[(Long, Double)]((1L, 2.5D), (2L, 0D), (3L, Double.NaN), (11L, 11D)).sortWith(_._2 < _._2)
output >>> Seq[(Long, Double)] = List((2,0.0), (1,2.5), (3,NaN), (11,11.0))
但在两者之间再次添加 NaN 会破坏排序
Seq[(Long, Double)] = List((2,0.0), (3,NaN), (1,2.5), (11,11.0))
output >>> Seq[(Long, Double)] = List((1,2.5), (3,NaN), (2,0.0), (11,11.0))
所以Seq.sortWith 或.sortBy 在看到NaN 时就决定放弃?
在一个稍微不相关的注释中,当我尝试对上述类型的元组序列进行排序时,spark 抛出了一个错误(如下)。上面的结果只是来自scala REPL,但没有涉及任何火花。
java.lang.IllegalArgumentException: 比较方法违反了它的一般约定!
在.max 和.min 上还有一个相关问题NaNs min/max of collections containing NaN (handling incomparability in ordering)
【问题讨论】:
-
不管怎样,下面的排序算法在
java.util.Arrays.sort内。