Я попытался запустить следующий код:
<script src = "https://d3js.org/d3.v7.min.js"></script>
<script>
console.info([10,2,3,7].sort(d3.ascending)); // 1
console.info([10,2,3,7].sort(d3.descending)); // 2
console.info([10,NaN,2,3,7].sort(d3.ascending)); // 3
console.info([10,NaN,2,3,7].sort(d3.descending)); // 4
console.info([10,undefined,2,NaN,3,7].sort(d3.ascending)); // 5
console.info([10,undefined,2,NaN,3,7].sort(d3.descending)); // 6
</script>
И расхождения в выводе между сортировкой по возрастанию и убыванию поставили меня в тупик.
CONSOLE OUTPUT:
[Log] [2, 3, 7, 10]
[Log] [10, 7, 3, 2]
**[Log] [2, 3, 7, 10, NaN]**
**[Log] [10, NaN, 7, 3, 2]**
[Log] [2, 7, 10, NaN, 3, undefined]
[Log] [10, 7, 2, NaN, 3, undefined]
Наблюдаемые учебные пособия D3, похоже, не затрагивают эту проблему. На самом деле, там есть некоторые другие моменты (относительно того, что d3.count() может подсчитывать строки), которые также оказались неверными, когда я запустил код. Поэтому я не мог полагаться на https://observablehq.com/@d3/
Кто-нибудь знает, ожидается ли вывод или почему порядок такой, как показано в выводе?
Я ожидал, что сортировка по-прежнему будет учитывать значения NaN и undefined и что-то с ними делать. Но я ожидаю некоторой согласованности между сортировкой по возрастанию и убыванию.
В JavaScript функция sort()
обрабатывает все нечисловые значения, такие как NaN
и undefined
. В JavaScript NaN
является особым значением и не равно никакому другому значению, в том числе и самому себе, поэтому при попытке отсортировать массив, содержащий NaN
, он появляется последним в порядке возрастания. undefined
это пропущенное значение и считается меньшим, чем любое другое значение, поэтому undefined
появляется последним как в порядке возрастания, так и в порядке убывания. Это поведение не характерно для D3, это просто язык JavaScript.
NaN появляется последним в порядке возрастания, так почему же тогда он появляется вторым в порядке убывания? **[Log] [2, 3, 7, 10, NaN]**
**[Log] [10, NaN, 7, 3, 2]**
Это проблема не D3, а javascript.
Если вы посмотрите на исходный код, единственное, что отличает по возрастанию от обычного сравнения (то есть (a, b) => a - b
), — это проверка null
перед сравнением чисел:
function ascending(a, b) {
return a == null || b == null ? NaN : a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
}
descending
— почти то же самое, но a
и b
поменяны местами.
Теперь вернемся к вашему вопросу. Прежде всего, вывод, который вы описали для третьего console.info()
, неверен, NaN
никогда не находится в последней позиции:
function descending(a, b) {
return a == null || b == null ? NaN : b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
}
function ascending(a, b) {
return a == null || b == null ? NaN : a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
}
console.info([10, NaN, 2, 3, 7].sort(ascending));
console.info([10, NaN, 2, 3, 7].sort(descending));
Здесь происходит то, что любое сравнение с NaN
вернет false
:
console.info(NaN > 42);
console.info(NaN < 42);
console.info(NaN === 42);
Поэтому ожидаем результаты D3 (а также обратите внимание, что между d3.ascending
и d3.descending
нет расхождений). На самом деле, вы получите те же результаты с простым JavaScript:
console.info([10, NaN, 2, 3, 7].sort((a, b) => a - b));
console.info([10, NaN, 2, 3, 7].sort((a, b) => b - a));
Наконец, стоит отметить, что, поскольку буква N
стоит после всех чисел, JavaScript sort
без функции сравнения поместит NaN
в конец (и "10"
перед "2"
, очевидно):
console.info([10, NaN, 2, 3, 7].sort());
Привет, спасибо, что нашли время, чтобы внести некоторую ясность. Теперь я понимаю, что d3.ascending и d3.descending на самом деле не играют здесь роли. Вывод такой же, как и при обычной сортировке Javascript. Однако я не понимаю, что вы подразумеваете под этим - «описанный вами вывод для третьего console.info() неверен, NaN никогда не находится в последней позиции». Я запустил фрагмент кода, который я опубликовал, а также простой код Javascript в последних двух фрагментах кода, включенных в ваш ответ, и вижу, что NaN находится на последней позиции. Не могли бы вы объяснить?
@aashima Sort зависит от реализации, вы, вероятно, используете Safari. Попробуйте Chrome или Firefox, вы увидите разницу.
Вау, ты прав! Я вижу другой результат в Chrome. Спасибо, это так помогло!
какой результат вы ожидаете для значений
null
иundefined
?