0

其中数据是以下格式的元数组,

[
  [
        "qux doo",
        "adsf",
        "abcd",
        "zzzz",
        "898jwe9"
  ],
  [
        "abcd",
        "xxrwu",
        "urnr",
        "pupupu",
        "sdsdsd"
  ]
]

以下两种算法是否会针对不同的输入数据值产生不同的结果?

data.sort(function(a,b){
  return (JSON.stringify(a) < JSON.stringify(b)) - (JSON.stringify(a) > JSON.stringify(b));
});

data.sort(function(a, b) {
    for (var i = 0; i < Math.min(a.length, b.length); i++) {
        if (a[i] < b[i]) return -1;
        if (a[i] > b[i]) return 1;
    } 
    return (a.length > b.length) - (a.length < b.length); 
});
4

1 回答 1

1

JSON.stringify()将转义一些字符(如双引号字符、反斜杠字符或任何控制字符),因此这些字符不太可能正确排序。

此外,由于空格的 ascii 代码低于双引号,因此如果您的两个数组以"abcd "and开头"abcd",它们将无法在 JSON 中正确排序。 "abcd "应该在 之后"abcd",但是空格的 ascii 值比双引号低,所以它会在之前排序。值末尾的感叹号也是如此。

如果根据您的评论,您还希望它适用于数字等非数组成员,则字符串比较不适用于比较具有不同位数的两个数字,因为1000不小于2,但"1000"小于"2"

另外,我建议您.localeCompare()在第二个算法中使用比较两个字符串,因为它已经具有内置的正、负或零结果。


如果您所有的值都是字符串或者它们通过 正确排序.toString(),您可以这样使用.localeCompare()

data.sort(function(a, b) {
    var comp, i;
    for (i = 0; i < Math.min(a.length, b.length); i++) {
        if ((comp = a[i].localeCompare(b[i])) !== 0) return comp;
    } 
    return (a.length > b.length) - (a.length < b.length); 
});

.localeCompare还有一些选项可用于区分大小写、忽略标点符号、如何处理重音字符以及其他一些选项。


根据您的评论和MDN,与 Collat​​or 对象(仅在某些浏览器中可用)相比,您可以获得更好的性能。根据文档(我自己只尝试过一次此代码),它的工作原理如下:

var collater = new Intl.Collator();
data.sort(function(a, b) {
    var comp, i;
    for (i = 0; i < Math.min(a.length, b.length); i++) {
        if ((comp = collater.compare(a[i], b[i])) !== 0) return comp;
    } 
    return (a.length > b.length) - (a.length < b.length); 
});

大概必须有一些初始化或开销可以通过这种方式完成一次。也许他们建立了直接查找排序表。

但是浏览器对 Collat​​or 对象的支持很少(IE 11、Chrome、没有 Firefox、没有 Safari),所以除非你在浏览器插件中使用它,所以代码只针对一个浏览器,你必须分支不管它是否被支持并且有两个实现。


PS 如果你有相当数量的外部数组元素,因此多次调用排序回调,它会执行得非常糟糕。你至少可以让它JSON.stringify()每次只打两次电话,而不是四次。

于 2013-11-15T02:49:32.023 回答