50

通过从

myArray.sort(function (a, b) {
  return a.name.localeCompare(b.name);
});

myArray.sort(function (a, b) {
  return (a.name < b.name ? -1 : (a.name > b.name ? 1 : 0));
});

我能够将在 Chrome 中对约 1700 个元素数组进行排序的时间从 1993 毫秒缩短到 5 毫秒。几乎是 400 倍的加速。不幸的是,这是以正确排序非英语字符串为代价的。

显然,当我尝试进行排序时,我的 UI 不能阻塞 2 秒。我能做些什么来避免极其缓慢的 localeCompare 但仍保持对本地化字符串的支持?

4

5 回答 5

44

通过预先声明collat​​or对象并使用它的 compare 方法,可以获得很大的性能改进。例如:

const collator = new Intl.Collator('en', { numeric: true, sensitivity: 'base' });
arrayOfObjects.sort((a, b) => {
  return collator.compare(a.name, b.name);
});

注意:如果元素是浮动的,这将无法正常工作。请参阅此处的说明:Intl.Collat​​or and natural sort with numeric options sorts wrong with decimal numbers

这是比较这 3 种方法的基准脚本:

const arr = [];
for (let i = 0; i < 2000; i++) {
  arr.push(`test-${Math.random()}`);
}

const arr1 = arr.slice();
const arr2 = arr.slice();
const arr3 = arr.slice();

console.time('#1 - localeCompare');
arr1.sort((a, b) => a.localeCompare(
  b,
  undefined, {
    numeric: true,
    sensitivity: 'base'
  }
));
console.timeEnd('#1 - localeCompare');

console.time('#2 - collator');
const collator = new Intl.Collator('en', {
  numeric: true,
  sensitivity: 'base'
});
arr2.sort((a, b) => collator.compare(a, b));
console.timeEnd('#2 - collator');

console.time('#3 - non-locale');
arr3.sort((a, b) => (a < b ? -1 : (a > b ? 1 : 0)));
console.timeEnd('#3 - non-locale');

于 2018-09-17T14:22:53.113 回答
13

我在处理 /mostly/ 拉丁字符时发现的一种有效方法是在两个字符串都匹配特定正则表达式时使用运算符。例如:/^[\w-.\s,]*$/

如果两个字符串都匹配表达式,它会快得多,而且在最坏的情况下,它似乎比盲目调用 localeCompare 稍微慢一些。

此处示例:http: //jsperf.com/operator-vs-localecompage/11

更新:似乎 Intl.Collat​​or 目前是全面性能的最佳选择:https ://jsperf.com/operator-vs-localecompage/22

于 2014-09-10T21:35:06.587 回答
6

如果不查看您正在排序的数据,很难知道最快的排序。但是 jsperf 有很多很好的测试显示排序类型之间的性能差异:http: //jsperf.com/javascript-sort/45 http://jsperf.com/sort-algorithms/31

然而,这些都没有考虑本地化字符串,我想没有简单的方法来对本地化字符串进行排序,而 localeCompare 可能是最好的解决方案。

查看 mozilla 的参考资料说:“在比较大量字符串时,例如在对大型数组进行排序时,最好创建一个 Intl.Collat​​or 对象并使用其 compare 属性提供的函数。” https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare

但是转到 Intl.Collat​​or 参考它表明不支持 firefox/safari https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Collat ​​or

您可以尝试使用 localCompare 上的一些选项来提高性能。但我刚刚做了一个更改灵敏度级别的快速测试,似乎它不会提高性能:

list.sort(function(a, b) {
  return a.localeCompare(b, {sensitivity:'base'});
});

http://jsperf.com/sort-locale-strings

于 2013-10-24T21:38:10.457 回答
2

尝试分两步对其进行排序:

  1. 与运营商:正如你所说,它会快400倍
  2. 然后使用localCompare(): 这现在要做的比较更少,因为数组大部分是排序的。

注意:我认为这localCompare()将主要用至少 1 个不是英文的字符串来调用。所以使用 2 个英文字符串的调用次数localCompare()应该会大大减少。

这是代码:

myArray.sort(function(a, b) {
  return (a.name < b.name ? -1 : (a.name > b.name ? 1 : 0));
});

myArray.sort(function(a, b) {
  return a.name.localeCompare(b.name);
});

该解决方案具有简短且易于使用的优点。如果数组主要包含英文字符串,这将是有效的。您拥有的非英语字符串越多,第一种类型的用处就越少。但是由于很容易添加到您的脚本中,因此也很容易看出这种方法是否值得。

现在,如果我是你,我也会使用,因为据说它比你有很多比较Intl.Collator要快得多。localCompare()

于 2015-05-24T11:57:13.617 回答
-3

我不知道你还在寻找解决这个问题的方法

// Defaulted to ascending
// 1 asc | -1 desc
var direction = 1; 
myArray.sort(function (a, b) {
  return a.name.localeCompare(b.name) === 1 ? direction : -1 * direction;
});

=== 1在您的代码中添加了一个检查,这个改进的性能提高了 400 倍,这意味着两者都有相当的性能数字。

具有 localeCompare arr 大小的性能编号:3200 10 次重复的平均时间:60 毫秒

使用 > 方法的性能数字。平均耗时 55 毫秒

于 2014-08-26T05:34:24.967 回答