8

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

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

字符串相当短,只有 15-25 个字符长。我的问题是我正在遍历很多字符串并且需要很长时间。

我在这样的结构中有很多比较:

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

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

4

4 回答 4

6

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

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

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

于 2013-11-11T09:52:36.340 回答
3

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

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”)和国际拼写(如“kilometres”)。)您可以提前准备该地图以避免创建开销。现在,给定一个变量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!

如果您的“做某事”不共享公共代码,您仍然可以使用地图,但它将是功能地图:

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]();

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

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

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
}

您可以将这些类型的测试相互嵌套到任何适合筛选您正在使用的特定字符串的程度。这是一种展开的二分搜索,尽管您所依据的条件不必将候选字符串精确地分成两组。

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

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

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

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

于 2013-11-12T16:06:27.053 回答
1

最快的 V8 方法是使用如下 switch 语句:

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!');
}

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

但是,如果您进行这些 if-else 比较,那么 JIT 优化器可能会也可能不会将这些比较优化为有效的东西。

允许 JIT 优化器对 switch 语句执行自己的优化可以更快的原因是因为当它只是比较长度时,它将能够对它比较的字符串的长度进行排序。这将使数字长度比较快得多(请参阅处理已排序 VS 未排序数组)。

于 2017-08-25T15:44:49.243 回答
1

我已经通过https://jsbench.me/做了一个基准测试。这些结果:

在此处输入图像描述

因此,正如Jack Giffin所说,在这种情况下 switch 语法是最快的。如果您正在做负比较器,那么结果会发生变化:

在此处输入图像描述

于 2019-05-16T15:10:57.707 回答