在JavaScript中比较字符串的最快方法是什么?

时间:2013-11-08 15:06:08

标签: javascript string performance string-comparison

我有两个字符串,我需要知道它们是否相等。

我之前已经这样做了:str1 === str2,但我想知道是否有更快的方法来比较两个字符串。

字符串相当短,长度为15-25个字符。我的问题是我正在迭代很多字符串,这需要相当长的时间。

我在这样的结构中进行了很多比较:

If(str === str1)
{
  do something
}
else if(str === str2)
{
  do something
}
else if(str === str3)
{
  do something
}

字符串没有任何共同的结构或分组。

4 个答案:

答案 0 :(得分:3)

将字符串与a === b进行比较是比较字符串原生的最快方法。

但是,如果您可以创建像new String("test")这样的字符串对象,重新使用它们并在比较中使用它们,那会更快,因为JS引擎只需要进行指针比较,是(少量)比字符串比较更快。

请参阅http://jsperf.com/string-vs-object-comparisons

答案 1 :(得分:2)

如果“do somethings”使用不同的值共享相似的表单,则可以将值放入映射中并将字符串用作键。例如,假设您必须处理具有不同长度单位的许多数字,并且您希望将它们全部转换为米:

var conversionToMeters = {
    "inch":   0.0254,
    "inches": 0.0254,
    "foot": 0.3048,
    "feet": 0.3048,
    "cubit":  0.4572,
    "cubits": 0.4572,
    "yard":  0.9144,
    "yards": 0.9144,
    "kilometer":  1000,
    "kilometers": 1000,
    "mile":  1609.344,
    "miles": 1609.344,
    "lightyear":  9.46e15,
    "lightyears": 9.46e15,
    "parsec":  3.09e16,
    "parsecs": 3.09e16,
}

(缩写(如“km”)和国际拼写(如“km”)为简洁而省略。)您可以提前准备该地图以避免创建开销。现在,给定变量length,例如length = "80 miles",您可以执行以下操作:

var magnitude = length.replace(/[\D]/g, "");
var unit = length.replace(/[\d\s]/g, "");
var lengthInMeters = magnitude * conversionToMeters[unit];
alert(lengthInMeters + " meters"); // Ta-da!

如果你的“做某些事情”不共享公共代码,你仍然可以使用地图,但它将是一个功能图(或基本上是一个JavaScript类):

var actions = {
    "eat": function() {
        if (spareFood > 0) {
            spareFood--;
            energy += 10;
            health++;
            alert("Yum!");
        }
    },
    "walk": function() {
        if (energy > 0) energy--;
        // ...
    },
    "attack": function() {
        if (energy > 0) {
            if (Math.random() < 0.25) {
                health--;
                alert("Ouch!");
            }
            energy--;
        }
    },
    // ...
};

这是一个愚蠢的例子,但我希望它解释了基本的想法。这些操作同样可以是XML标记,虚拟机中CPU指令的名称,或具有特殊运输要求的产品的名称,或其他。获得action变量后,执行它就像:

一样简单
actions[action]();

地图并不是做这种事情的唯一方法。您可以通过将ifs嵌套在旨在快速消除大多数候选字符串的其他ifs中来轻松优化您的原始if / else示例。

您分支的标准取决于您正在使用的确切字符串。它可以是字符串的长度,或第一个字母,或几个最有区别的字母:

if (str.length === 3) {
    // test all length 3 strings here
    if (str === strA) doSomething();
    else if (str == strB) doSomething();
} else if (str.length === 4) {
    // test all length 4 strings here
    if (str === strC) doSomething();
    else if (str === strD) doSomething();
}

或者:

var first = str[0]; // first character
if (first >= "0" && first <= "9") {
    // test all strings that start with digits here
if (first >= "a" && first <= "l") {
    // test all strings that start with letters
    // in the first half of the alphabet here
} else if (first >= "m" && first <= "z") {
    // test all strings that start with letters
    // in the latter half of the alphabet here
}

您可以将这些类型的测试嵌套在一起,以适合筛选您正在使用的特定字符串的任何程度。这是一种展开的binary search,尽管您分支的标准不必将候选字符串分成两组。

此外,当你使用像这样的if / elseif时,通常值得按频率的降序排列字符串。即,首先测试发生最多的那些。如果只有几个字符串构成了大部分数据,请将它们拉到顶部,甚至将它们放在任何基于长度或首字母的预测试之外。

您必须决定是否值得做这些事情:如果您将这些技术发挥到极致,您可能会获得额外的性能优势,但会牺牲可读性和可维护性。

P.S。我不太清楚JavaScript,不知道这些技术将如何执行,但我在Java中做过类似的事情。在Java中,当“do somethings”需要不同的值但可以使用相同的代码时,map方法是无与伦比的。在另一个程序中,我需要switch对一个整数值执行大约400个不同的操作(这很糟糕)。 HotSpot客户端虚拟机的switch语句实现效率很低,只是很多其他的,而且速度太慢。函数数组(技术上是具有重写的虚方法的对象)更快,但与每个操作的简单性相比,函数调用开销太大。在这种情况下,我发现混合二进制四元搜索是有效的。这意味着:外部测试是if / elses将输入值均分为两组。这些嵌套直到内部组中只剩下四个可能的值。然后我用if / elseif / elseif / else来区分剩下的四个值。由于这个时间太长了,我写了一些代码来为我编写代码,但对于这个特定的应用程序仍然值得努力。

P.P.S。我跳过上面的方法,但我会将其包含在内以便完整:如果您的字符串很少需要更改,则可以使用perfect hash function。有一些实用程序可以为您设计这些功能:只需为它们提供所有字符串的列表即可。完美的哈希函数将从字符串计算整数哈希码,并保证您的集合中没有两个字符串具有相同的哈希码。然后,您可以使用整数哈希码来查找数组中的操作。它对解析编程语言的关键字很有帮助。在一种更接近金属的语言中它可以更快,但在JavaScript中我怀疑它不值得。我提到它是为了以防万一。

答案 2 :(得分:1)

最快的V8方式是使用如下的开关语句:

&#13;
&#13;
var str = '' + prompt('Enter cat or enter in dog');
switch(''+str){ // make it clear you are switching on a string
  case 'cat':
    console.log('you selected cat!');
    break;
  case 'dog':
    console.log('you selected dog!');
    break;
  default:
    console.log('you selected something else!');
}
&#13;
&#13;
&#13;

为什么这是最快的方法的原因是因为它将为JIST优化器提供更多优化比较的机会。例如,它可能执行的一种可能的优化是在进行任何实际比较之前先抢先搜索相同长度的字符串。

但是,如果你进行if-else比较,那么JIST优化器可能会也可能无法将这些比较优化为有效的。

为什么允许JIST优化器在switch语句上执行自己的优化的原因可能更快,因为当它只是比较长度时,它将能够对它所比较的​​字符串的长度进行排序。这将使数字长度比较更快(参见Proccessing Sorted VS Unsorted Array)。

答案 3 :(得分:0)

我已经进行了基准测试https://jsbench.me/。这些结果在哪里:

enter image description here

因此,正如Jack Giffin所说,在这种情况下,开关语法是最快的。如果您要使用负比较器,则结果将更改:

enter image description here