2017-02-22 22 views
2

Я столкнулся с очень странным поведением сортировки в scala (2.11.8 и 2.12.1) для Seq[(Long, Double)]. Я, наверное, неправильно понимаю что-то фундаментальное.scala Seq sortWith или sortBy с NaNs

Учитывая последовательность без каких-либо 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 или в моем мозгу? Я использую scala 2.11.8 и 2.12.1 на Ubuntu 16.04 и Java 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)) 

So Seq.sortWith или .sortBy просто решает сдаться, когда он ees a NaN?


На слегка несвязанной ноте, я наткнулся на это как spark бросает ошибку (ниже), когда я пытался разобраться последовательность кортежей указанного вида. Результаты, приведенные выше, относятся только к scala REPL, хотя в нем нет искры.

java.lang.IllegalArgumentException: метод сравнения нарушает его общий контракт!


есть также связанный с ним вопрос о .max и .min с NaN сек min/max of collections containing NaN (handling incomparability in ordering)

+1

Для чего это стоит, алгоритм сортировки под ним находится в 'java.util.Arrays.sort'. –

ответ

5

искру, за исключением является на самом деле очень хороший намек на то, что происходит здесь: Spark предполагает, что метод сравнения определяет Total Order на входе, что означает, среди прочего, что для каждых двух элементов в наборе:

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'. Это становится нашим, потому что я использую '>', а не '<' - см. Обновление выше. –

+0

Это не просто транзитивность. Сортировка предполагает общий порядок. Таким образом, либо A <= C, либо C

 Смежные вопросы

  • Нет связанных вопросов^_^