2017-02-22 7 views
2

Seq[(Long, Double)]の場合、スカラー(2.11.8および2.12.1)で非常に奇妙なソート動作が発生しました。おそらく私は何か基本的なことを誤解しているでしょう。scala Seq sortWithまたはsortBy(NaNの場合)

私はソート列に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)]((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)) 

すべてが期待どおりに動作することでno Double.NaN値でシーケンスを考えます何もしなかった

最初の2つの要素を交換する場合

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)で観察されます。これはスカラー、または私の脳のバグですか?私はスカラー2.11.82.12.1Ubuntu 16.04Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_91に使用しています。

更新

それは私がソート順序を逆ならば、少しより予測可能なものが

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はちょうどea a NaN?やや無関係なノートで


私は上記の種類のタプルの順序を並べ替えるしようとしていたときspark(下)エラーを投げていたとして、私はこれに出くわしました。上記の結果は、scala REPLからのものですが、スパークはありません。

java.lang.IllegalArgumentException:比較方法が一般契約に違反しています。


.max.minに関連する質問がNaNmin/max of collections containing NaN (handling incomparability in ordering)

+1

それは価値があるため、ソートアルゴリズムは 'java.util.Arrays.sort'の中にあります。 –

答えて

5

でもありますスパーク例外は、ここで何が起こっているのかに関して、実際には本当に良いヒントです:スパークは、比較方法がを定義すると仮定し入力セットにTotal Orderが含まれます。これは、とりわけ、セット内の2つの要素ごとに、

A > B OR B > A 

今度は、関数_ > _はダブルスのトータルオーダーですが、であり、すべてのダブルとNaNの合計ではありません。これは、これらの簡単なテストを使用して見ることができます。

scala> Double.NaN > 1.0 
res19: Boolean = false 

scala> Double.NaN < 1.0 
res20: Boolean = false 

ので、NaNが1.0よりも大きくも小さくありません。

sortWithの実装に戻る - 私はチェックしませんでしたが、同じ仮定をしていると仮定していますが、そうでない場合にエラーをスローするのではなく、その結果は単に予測できません全体が壊れたとき

EDIT

のでSeq.sortWithまたは.sortByはちょうどそれがNaNを見たときあきらめることにしましたか?

いいえ、それは、前提が維持されていないために間違った決定をするため、単に「間違った」結果を返します。 テストは、NaNを探していて、あきらめています(@TheArchetypalPaulとしてコメントしました:「すべての値が比較前にNaNでないことを確認する必要があります。

+0

私にそれを打つ。私はちょうど非常に類似した何かをタイプしていた! –

+0

私は推移部分を得て、私はまだ言語がNaNを一貫した方法で扱うことを期待しています。おそらく彼らの位置を変えないかもしれません。また、 'sortBy'は' sortWith'で壊れていないことに注意してください。これは私が '>'ではなく '<'ではないからです - 上記のupdateを見てください。 –

+0

これは単なる推移性ではありません。並べ替えは合計順序を前提としています。だから、A <= CまたはC

関連する問題