web-dev-qa-db-ja.com

日付で配列をソートすると、予期しない結果が生じます

これは簡単な問題のように聞こえますが、私は日曜日を以下に説明する実装の何が問題なのかを理解しようとしていたので、最後の手段として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 で問題なく動作するため、間違いなく問題ではありません!このコードに何か問題がありますか?

28
GETah

短い答え

ブール値ではなく、2つの日付の差を返す必要があります。

_// 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に渡された匿名関数は、sort関数のネイティブ実装のコンパレータとして機能します。

ただし、負の値は_-1_である必要はなく、正の値は_+1_である必要はありません。したがって、数字を並べ替えるときは、代わりにショートカットを使用できます。

_yourArray.sort(function (a, b) {
    return a - b
})
_

JavaScriptでは、2つの日付を減算すると、両方が強制的に数値に変換されるため、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_を返さないことを意味します。したがって、要素は正しくソートされません。

130
royhowie
let _sortedDates = dates.sort(function(a, b){
  return moment(b).format('X')-moment(a).format('X')
});

モーメントは有効な日付をフォーマットできるので、日付をタイムスタンプにフォーマットするときは、基本的に番号でソートするように、ソートメソッドjavascriptを使用するのが最善の方法です。

参照:momentjs.com/docs/#/displaying/format、w3schools.com/jsref/jsref_sort.asp

4
Ylli Gashi