在Chrome中对对象数组进行排序

时间:2010-07-07 14:53:04

标签: javascript sorting google-chrome

编辑:正如下面的kennytm所述,在调查自己之后,根据ECMA spec,当两个对象在自定义排序中被确定为相等时,JavaScript需要 才能离开这两个对象的顺序相同。 Chrome和Opera是唯一两种选择不稳定排序的主要浏览器,但其他浏览器包括Netscape 8& 9,Kazehakaze,IceApe和其他一些浏览器。 Chromium团队已将此错误标记为“按预期工作”,因此不会“修复”。如果您需要数组在值相等时保持其原始顺序,则需要使用一些其他机制(例如上面的那个)。排序对象时返回0实际上没有意义,所以不要打扰。或者使用支持稳定排序的库,例如Underscore / Lodash。


我刚刚得到一份报告,我写的一些代码在Chrome上打破了。我已经将它跟踪到我用于对对象数组进行排序的自定义方法。我真的很想把它称为一个错误,但我不确定是不是。

在对所有其他浏览器排序对象数组时,如果两个对象解析为相同的值,则更新后的数组中的顺序保持不变。在Chrome中,他们的订单似乎是随机的。在Chrome和您想要的任何其他浏览器中运行以下代码。你应该明白我的意思。

我有两个问题:

首先,我是否正确地假设当您的自定义排序器返回0时,两个比较项应该保持其原始顺序(我有一种感觉我错了)。

第二,有什么好方法可以解决这个问题吗?我唯一能想到的是在排序之前将自动递增数字作为属性添加到数组的每个成员,然后在两个项sort将resolve与同一值进行比较时使用该值。换句话说,永远不要返回0。

以下是示例代码:

var x = [
{'a':2,'b':1},
{'a':1,'b':2},
{'a':1,'b':3},
{'a':1,'b':4},
{'a':1,'b':5},
{'a':1,'b':6},
{'a':0,'b':7},
]

var customSort = function(a,b) {
    if (a.a === b.a) return 0;
    if (a.a > b.a) return 1;
    return -1;
};

console.log("before sorting");
for (var i = 0; i < x.length; i++) {
    console.log(x[i].b);
}
x.sort(customSort);

console.log("after sorting");
for (var i = 0; i < x.length; i++) {
    console.log(x[i].b);
}

在所有其他浏览器中,我看到的是只有第一个成员和数组的最后一个成员被移动(我看到7,2,3,4,5,6,1)但在Chrome中,内部数字似乎是随机的。

[编辑]非常感谢所有回答的人。我想“不一致”并不一定意味着它是一个错误。另外,我只想指出我的b属性只是一个例子。事实上,我根据用户输入在大约20个键中的任何一个上排序一些相对宽的对象。即使跟踪用户最后排序的内容仍然无法解决我看到的随机性问题。我的解决方案可能是这方面的一个近似变化(新代码突出显示):

var x = [
{'a':2,'b':1},
{'a':1,'b':2},
{'a':1,'b':3},
{'a':1,'b':4},
{'a':1,'b':5},
{'a':1,'b':6},
{'a':0,'b':7},
];
var i;

var customSort = function(a,b) {
    if (a.a === b.a) return a.customSortKey > b.customSortKey ? 1 : -1; /*NEW CODE*/
    if (a.a > b.a) return 1;
    return -1;
};

console.log("before sorting");
for (i = 0; i < x.length; i++) {console.log(x[i].b);}

for (i = 0; i < x.length; i++) {                      /*NEW CODE*/
    x[i].customSortKey = i;                           /*NEW CODE*/
}                                                     /*NEW CODE*/
x.sort(customSort);

console.log("after sorting");
for (i = 0; i < x.length; i++) {console.log(x[i].b);}

3 个答案:

答案 0 :(得分:22)

ECMAScript标准does not guarantee Array.sort is a stable sort。 Chrome(V8引擎)使用in-place QuickSort internally(对于大小≥22的数组,否则插入排序),但速度很快not stable

要解决此问题,请将customSort.b进行比较,从而消除排序算法的稳定性。

答案 1 :(得分:8)

不幸的是,V8排序并不稳定。我会看看我是否可以挖掘出关于此的Chromium bug。

答案 2 :(得分:8)

可能您已经知道了,但您可以使用数组对多列进行排序并避免此错误:

var customSort = function(a,b) {
    return [a.a, a.b] > [b.a, b.b] ? 1:-1;
}