【问题标题】:Fast way to find if a string is in an array快速查找字符串是否在数组中的方法
【发布时间】:2013-10-28 20:31:33
【问题描述】:

在 Ruby 中,查找字符串是否在数组中 (.include? x) 非常慢。如果您将该数组更改为一个集合,则 BAM,快速查找。

在没有集合的 JavaScript 中,数组查找 (.indexOf(x) >= 0) 也非常很慢,但是我需要在脚本中执行 10,000 次这样的查找。

我的 Ruby 版本(带有集合)在 0.125 秒内运行,我的 JavaScript 版本(在 NodeJS 中)需要 29

是否有任何集合库或更好的方法来执行数组查找,可以获得接近 Ruby 的 Javascript 速度?

编辑:将“对象”更改为“字符串”以消除任何混淆

【问题讨论】:

  • 对象的结构是什么?如果它们具有某种唯一的 id 属性,则可以使用该 id 作为键将它们存储在对象中。
  • @nnnnnn 这只是一个字符串数组 (["foo", "bar", "baz"])。抱歉,我没有说清楚。
  • 唯一字符串?尝试对象var o = {"foo":1,"bar":1,"baz":1},然后尝试if ("foo" in o) { /*exists*/ }
  • 你试过上面提到的"string" in foo 计时吗?
  • @asifrc 哇,它完美无瑕!脚本在0.250 秒内完成!谢谢大家!

标签: javascript arrays set


【解决方案1】:

首先,对于 JavaScript 中可用的数据结构存在一些根本性的混淆。

TL;DR

  • 如果您想以最快的速度查找具有短原型继承链的对象,请使用in

  • 如果你想要相同,但对于具有广泛继承链的对象,请使用Object.prototype.hasOwnProperty

  • 如果您想要最快的值查找,请将Array.prototype.indexOf 用于Array

  • 没有用于在哈希表中查找值的内置函数。当然,您可以自己开发,但是已经有很多库提供了。例如,Underscore 提供了一个(它称之为indexOf)。

JavaScript 没有数组

从根本上说,JavaScript 只有哈希表。标准的 Array 函数构造哈希表(我将这些称为 integer hash-tablesint-hash-tables),其中键是除字符串之外的整数键。这些执行类似于数组,但它们在某些方面有所不同。有缺点也有优点。例如,从 int-hash-table 中删除一个元素是 O(1) 操作,而从数组中删除一个元素是 O(n) 操作(因为您需要将其余元素复制到新数组中)。这就是为什么 JavaScript 中的 Array.prototype.splice 函数非常快的原因。缺点是实现的复杂性。

所以,当你在 JavaScript 上下文中说 Array 时,它被理解为 int-hash-table,以及与之相关的所有渐近复杂性。这意味着如果你想在一个 int-hash-table 中找到一个字符串 value,那么这将是一个 O(n) 操作。有一个标准函数:Array.prototype.indexOf。但是,如果您想查找 key,则有两个函数:inObject.prototype.hasOwnProperty

有点违反直觉:

[1, 2, 3].hasOwnProperty(0); // true
0 in [1, 2, 3]; // true

两者的区别需要进一步解释。这与 JavaScript 中的所有事物都是对象这一事实有关,因此它们具有一些对象特性。其中之一是prototype,它是对象与其原型之间的链接。它是一种哈希表的层次结构,每个哈希表都包含对象的属性。

  • in 查找对象的直接哈希表,然后递归搜索该对象原型的哈希表。

  • Object.prototype.hasOwnProperty 只查看直接哈希表。您可能认为它应该更快,但请稍等片刻。

由于 JavaScript 的动态特性,所有函数调用都是动态的,环境必须非常小心以确保代码执行故障安全。这意味着在 JavaScript 中函数调用非常昂贵。因此,通过Object.prototype.hasOwnProperty 可能比通过in 贵很多,即使理论上它应该是相反的。但是,鉴于足够高的继承树和足够多的继承属性,最终,Object.prototype.hasOwnProperty 将接管。

一些例子以获得更好的直觉:

>>> var array = [1, 2, 3];
undefined
>>> 3 in array;
false
>>> array.hasOwnProperty(3);
false
>>> 3 in array;
false
>>> array.__proto__ = [1, 2, 3, 4];
[1, 2, 3, 4]
>>> 3 in array;
true
>>> array.hasOwnProperty(3);
false

【讨论】:

【解决方案2】:

来自 cmets 中的@nnnnnn:

将数组转换为对象,如下所示:

object = {}
array.forEach(function(string) { // Not cross-browser compatible, it's just an example
  object[string] = 1;
}

然后像这样执行查找:

if (string in object) {

【讨论】:

    猜你喜欢
    • 2021-12-28
    • 2015-01-14
    • 2016-06-18
    • 1970-01-01
    • 2011-02-05
    • 1970-01-01
    • 2017-01-02
    • 1970-01-01
    • 2018-01-03
    相关资源
    最近更新 更多