Есть пара тонких вещей происходит Здесь. Это не обычная проблема с «сломанным компаратором», рассмотренная в другом месте в Stack Overflow. Хотя этот компаратор действительно сломан, его довольно сложно увидеть.
Первая проблема заключается в том, что компаратор несет основную ответственность за сравнение значений Double
, то есть в штучной упаковке double
значений. Принимая во внимание, что оператор >
выполнит автоматическую распаковку и проведет цифровое сравнение содержащихся значений, оператор ==
проверит ссылочное равенство. В общем,
Double.valueOf(1.23) == Double.valueOf(1.23) // WARNING: reference comparison, not numeric!
будет false
. Если вы действительно хотите, чтобы проверить числовое равенство Double
значений, вы должны были бы сделать
if (o1.getValue().doubleValue() == o2.getValue.doubleValue()) ...
Это будет в основном работать, если ваш вход содержит только фактические числовые значения. Я подозреваю, однако, что ваш ввод содержит значения NaN
, которые имеют неясное (даже бессмысленное) поведение. В частности, сравнение NaN
с любым числовым значением ложно, а NaN
сравнивает не равное себе! Это нарушает правила всех типов о числовых сравнениях; Действительно, NaN
неупорядочен относительно действительных чисел. Вот почему алгоритм сортировки ломается, когда он встречает значения NaN
.
(NaN
является результатом деления 0.0 на 0.0, между прочим.)
Существует метод, который обрабатывает Double.compare(double d1, double d2)
NaN
разумно; он сортирует NaN
значениями выше Double.POSITIVE_INFINITY
. (Он также отличает положительный ноль от отрицательного нуля, но это вряд ли вызовет вашу проблему.) Существует сопутствующий метод Double.compareTo(Double)
, который сравнивает значения в ящике Double
.
Я бы переписать компаратор так:
Collections.sort(res, new Comparator<Entry<Integer, Double>>() {
public int compare(Entry<Integer, Double> o1,
Entry<Integer, Double> o2) {
if (isDesc) {
return o2.getValue().compareTo(o1);
} else {
return o1.getValue().compareTo(o2);
}
}
}
Поскольку Double
является Comparable
самим, в Java-вы можете избежать написаний собственного компаратора с использованием методы полезности на Map.Entry
. Вы можете также использовать метод по умолчанию sort()
на List
, который будет быстрее в целом:
if (isDesc) {
res.sort(Map.Entry.<Integer,Double>comparingByValue().reversed());
} else {
res.sort(Map.Entry.comparingByValue());
}
(К сожалению, вывод типа не совсем работа, поэтому вы должны обеспечить «тип свидетеля», чтобы получить обратный компаратор.)
Наконец, вы можете использовать оператор «бриллиант» и конструктор копирования ArrayList
, чтобы скопировать записи в карты гораздо более сжато. Переписанная процедура выглядит так:
public static List<Entry<Integer, Double>> sortMap(
Map<Integer, Double> curMap, final boolean isDesc) {
List<Entry<Integer, Double>> res = new ArrayList<>(curMap.entrySet());
if (isDesc) {
res.sort(Map.Entry.<Integer,Double>comparingByValue().reversed());
} else {
res.sort(Map.Entry.comparingByValue());
}
return res;
}