Сортировка массива по дате дает неожиданные результаты

Это будет звучать как простая проблема, но я провел свое воскресенье, пытаясь выяснить, что не так с моей реализацией, описанной ниже, поэтому я отправляю ее в 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