按日期排序数组会产生意想不到的结果
Sort array by date gives unexpected results
这听起来是个简单的问题,但我整个星期天都在试图弄清楚下面描述的我的实现有什么问题,所以我将它发布到 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;
});
问题
这是我从服务器收到的数据样本:
注意末尾未分类的项目。
seriesRawDataArray.sort
似乎对原始数组没有影响,无论我在排序方法中更改什么,原始数组都不会排序。输出总是:
注意这里的未排序元素。
我正在使用的库和数据绝对不是问题,因为这个 jsfiddle 工作得很好!
这段代码有问题吗?
简答
您应该 return 两个日期之间的差异,而不是布尔值:
// 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
期望 return 为负值、零值或正值。通常,您会像这样编写排序函数:
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
}
})
传递给排序的匿名函数用作排序函数的本机实现的比较器。
但是,您的负值不必是 -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
)
但是,在您的代码中,您return编辑了diff > 0
,它可以是true
或false
。由于类型强制,JavScript 会将 true
读作 1
,将 false
读作 0
。这意味着您的排序函数永远不会 return -1
。因此,您的元素将无法正确排序。
let sortedDates = dates.sort(function(a, b){
return moment(b).format('X')-moment(a).format('X')
});
既然可以格式化有效日期,最好的方法就是使用排序方法javascript,所以在将日期格式化为时间戳时,基本上是按数字排序。
参考文献:
这听起来是个简单的问题,但我整个星期天都在试图弄清楚下面描述的我的实现有什么问题,所以我将它发布到 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;
});
问题
这是我从服务器收到的数据样本:
注意末尾未分类的项目。
seriesRawDataArray.sort
似乎对原始数组没有影响,无论我在排序方法中更改什么,原始数组都不会排序。输出总是:
注意这里的未排序元素。 我正在使用的库和数据绝对不是问题,因为这个 jsfiddle 工作得很好! 这段代码有问题吗?
简答
您应该 return 两个日期之间的差异,而不是布尔值:
// 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
期望 return 为负值、零值或正值。通常,您会像这样编写排序函数:
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
}
})
传递给排序的匿名函数用作排序函数的本机实现的比较器。
但是,您的负值不必是 -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
)
但是,在您的代码中,您return编辑了diff > 0
,它可以是true
或false
。由于类型强制,JavScript 会将 true
读作 1
,将 false
读作 0
。这意味着您的排序函数永远不会 return -1
。因此,您的元素将无法正确排序。
let sortedDates = dates.sort(function(a, b){
return moment(b).format('X')-moment(a).format('X')
});
既然可以格式化有效日期,最好的方法就是使用排序方法javascript,所以在将日期格式化为时间戳时,基本上是按数字排序。
参考文献: