Сортировка массива по дате дает неожиданные результаты
Это будет звучать как простая проблема, но я провел свое воскресенье, пытаясь выяснить, что не так с моей реализацией, описанной ниже, поэтому я отправляю ее в SO в качестве последнего средства.
У меня есть приложение JavaScript, которое получает структуры данных с сервера. Серверная часть отправляет данные несортированными по соображениям производительности.
Вот фрагмент кода JavaScript, получающего данные:
var seriesRawDataArray = ko.observableArray();
...
analyticscontext.series(seriesRawDataArray).done(function () {
renderSeries();
});
Модуль analyticscontext
запрашивает данные, используя ajax:
function series(seriesData) {
return $.ajax({
url: "/api/analytics/series",
type: "GET",
success: function (data) {
return seriesData(data);
}
});
}
renderSeries
выполняет сортировку данных перед их отображением:
// Sort the data by date using moment.js
seriesRawDataArray.sort(function (left, right) {
var leftDate = moment.utc(left.timeStamp);
var rightDate = moment.utc(right.timeStamp);
var diff = leftDate.diff(rightDate);
return diff > 0;
});
ПРОБЛЕМА
Вот пример данных, которые я получаю с моего сервера:
![enter image description here]()
Обратите внимание на несортированные элементы в конце.
seriesRawDataArray.sort
, похоже, не влияет на исходный массив, который не сортируется, независимо от того, что я изменяю в методе сортировки. Выход всегда:
![enter image description here]()
Обратите внимание на несортированные элементы здесь.
Библиотеки, которые я использую, и данные определенно не проблема, так как этот jsfiddle работает просто отлично!
Что-то не так с этим кодом?
Ответы
Ответ 1
короткий ответ
Вы должны вернуть разницу между двумя датами, а не логическими:
// sort the data by date using moment.js
seriesRawDataArray.sort(function (left, right) {
return moment.utc(left.timeStamp).diff(moment.utc(right.timeStamp))
});
почему
Array.prototype.sort
ожидает возврата отрицательного, нулевого или положительного значения. Как правило, вы будете писать функцию сортировки следующим образом:
yourArray.sort(function (a, b) {
if (a < b) { // a comes first
return -1
} else if (b < a) { // b comes first
return 1
} else { // equal, so order is irrelevant
return 0 // note: sort is not necessarily stable in JS
}
})
Анонимная функция, переданная в sort, служит в качестве компаратора для собственной реализации функции сортировки.
Однако ваше отрицательное значение не должно быть -1
, и ваше положительное значение не должно быть +1
. Поэтому при сортировке чисел вы можете использовать ярлык:
yourArray.sort(function (a, b) {
return a - b
})
В JavaScript вычитание двух дат коэрцирует их обоих в числа, поэтому мы можем использовать return moment.utc(left.timeStamp).diff(moment.utc(right.timeStamp))
(вместо прямого вычитания -
этот метод использует moment.prototype.diff
из библиотеки moment.js
)
Однако, в вашем коде вы вернули diff > 0
, который может быть либо true
, либо false
. Из-за принуждения типа JavScript будет читать true
как 1
и false
как 0
. Это означает, что ваша функция сортировки никогда не вернет -1
. Поэтому ваши элементы не будут правильно отсортированы.
Ответ 2
let sortedDates = dates.sort(function(a, b){
return moment(b).format('X')-moment(a).format('X')
});
Поскольку момент может форматировать действительные даты, лучшим способом является использование метода сортировки javascript, поэтому при форматировании даты по метке времени, в основном, вы сортируете по номеру.
Рекомендации:
http://www.momentjs.com/docs/#/displaying/format
http://www.w3schools.com/jsref/jsref_sort.asp