按日期排序数组会产生意外结果

时间:2015-01-18 18:08:48

标签: javascript arrays sorting knockout.js

这听起来很简单,但我花了我的星期天试图找出下面描述的实施方法有什么问题,所以我将它作为最后的手段发布到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工作得很好! 这段代码有问题吗?

2 个答案:

答案 0 :(得分:125)

简短回答

您应该返回两个日期之间的差异,而不是布尔值:

// 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中,减去两个日期会将它们强制转换为数字,这就是我们可以使用return moment.utc(left.timeStamp).diff(moment.utc(right.timeStamp))

的原因

(而不是直接减法-,此方法使用moment.js库中的moment.prototype.diff

但是,在您的代码中,您返回了diff > 0,可以是truefalse。由于类型强制,JavScript会将true读为1,将false读为0。这意味着您的排序函数永远不会返回-1。因此,您的元素将无法正确排序。

答案 1 :(得分:4)

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