我有一个JavaScript对象数组。我想用一个特定的度规来排序。在特殊情况下,度规每次都有相同的值。下面是一个示例数组:
var myArray = [{"key":400686,"metric":999999},{"key":52601288,"metric":999999},{"key":1380180030,"metric":999999},{"key":909661,"metric":999999},{"key":401336,"metric":999999},{"key":1317275,"metric":999999},{"key":8642696,"metric":999999},{"key":1374360020,"metric":999999},{"key":602871933,"metric":999999},{"key":410174,"metric":999999},{"key":503411,"metric":999999},{"key":401511,"metric":999999},{"key":410196,"metric":999999},{"key":419377,"metric":999999},{"key":429167,"metric":999999},{"key":609656,"metric":999999},{"key":837941,"metric":999999},{"key":2410791,"metric":999999},{"key":4501004,"metric":999999},{"key":8633371,"metric":999999},{"key":1356540155,"metric":999999},{"key":1374360757,"metric":999999}];
当我做这样简单的调用时:
myArray.sort( function( a, b ){ return 0; } );
数组被排序了!显然,它应该保持不变,因为排序函数中的返回值为0表示相等。
还有其他人遇到过这个问题吗?
0表示相等,这意味着元素是可互换的。这并不意味着它们不会被移动。这意味着它们可以自由交换或保持在原来的位置,数组仍然会被排序。
这是因为排序是不稳定的,它不一定保持相等项的相对顺序。
您可以使用稳定的排序算法,如归并排序。
如果您希望将相同的元素按可预测的顺序排序,那么您需要一个辅助键来识别哪些相同的元素应该在其他元素之前。在您的示例数组中,您可以使用如下的自定义排序函数,该函数将首先按度量排序,如果它们相同,则按键排序:
myArray.sort( function( a, b ){
if (a.metric != b.metric) {
return(b.metric - a.metric);
}
// when metrics are the same, sort by key as secondary sort
return(b.key - a.key)
});
或者,如果您希望保留相同元素的现有顺序,那么您需要在每次排序之前快速传递以添加顺序值:
// mark each value with it's current position in the array
for (var i = 0; i < myArray.length; i++) {
myArray[i].sortIndexForTies = i;
}
myArray.sort( function( a, b ){
if (a.metric != b.metric) {
return(b.metric - a.metric);
}
// when metrics are the same, sort by the original array position as second sort key
return(b.sortIndexForTies - a.sortIndexForTies)
});
我发现了一个很好的解决方法,我通过在排序参数上添加一个delta来使排序偏离我所关心的精度。偏差使数组倾向于保持相同的顺序。如果在距离上有一个单位的差异(我的精度是在15位),该元素将被正确排序。
for( var i = 0, len = myArray.length, delta = 0; i < len; i++, delta += 0.000001 )
{
myArray[ i ].metric -= delta;
}
function byMetric( a, b )
{
return b.metric - a.metric;
}
myArray.sort( byMetric );