【问题标题】:Performance of OR operation ( || ) vs inArray()OR 运算 ( || ) 与 inArray() 的性能
【发布时间】:2012-05-15 18:46:33
【问题描述】:

假设您要检查用户在表单字段中输入的输入字符串。哪一种方法是根据可能值列表检查此输入的最快方法?

以下示例使用 jQuery

第一种方法:使用||

if (input == "firstValue" || input == "secondValue" || ... ) {
    ...
}

第二种方法:使用inArray()

if ($.inArray(input, array) >= 0) {
    ...
}

这两种方法有什么显着差异吗?

【问题讨论】:

  • 两者都具有 O(n) 最坏情况复杂度,其中 n 是您正在测试的事物的数量,唯一的性能提升是一个不是函数调用,而另一个是。
  • 你说的真的是 JavaScript 吗?
  • 然而,在实际层面上,我更倾向于inArray() 之类的东西,因为它对于大型复核数据集具有更大的动态潜力。以及更容易阅读。试想一下,如果我们有 10 个左右的值要反查! :D
  • @Niko ~ 实际上可能是 jQuery。 api.jquery.com/jquery.inarray
  • @Niko LOL 抱歉,标签错误:D 已编辑

标签: javascript jquery performance


【解决方案1】:

答案是,视情况而定...

如果只有几种可能,请使用if (a || b || c)

如果可能多达 10 个,请使用 Array.indexOf()

请注意,对于上述两个建议,选择应取决于可读性,而不是真正的性能。

如果有(很多)更多,请使用键等于值的Object,然后您可以使用if (myVar in myKeyObj)。这应该提供最差的O(log n) 性能。

【讨论】:

  • 我认为他错误地标记了这个问题。他的代码是 PHP,而不是 JavaScript。
  • @ThiefMaster 为什么你会认为它是 PHP?事实上,他使用美元前缀? :) 话虽如此,他确实依赖于 inArray 的布尔结果......这令人困惑
  • 我已经编辑了这个问题,以明确我正在使用 jQuery。
  • O(log n)?假设 JavaScript 使用哈希表进行对象键查找,它会是 O(1),不是吗?
  • @ThiefMaster 这将取决于实现 - 我怀疑 ES5 标准指定了它。
【解决方案2】:

在使用 javascript 时,性能通常不是什么大问题,而且通常是很难回答的问题。

在此示例中,解决方案之间的主要区别在于缩放。第一个解决方案总是会进行预定数量的比较,inArray 解决方案的扩展性更差,因为如果有更多的值,它会比较更多。

但是我仍然会选择 inArray,99.99% 的机会性能真的无关紧要。你想让你的代码保持可维护性,这很重要。

【讨论】:

  • The first solution will always do a predetermined amount of compares,我认为如果 || 中的任何一个为真,javascript / php 会提前退出?
  • 正确,所以最大值是已知的。
  • 啊,我现在明白你所说的predetermined 是什么意思了。谢谢
  • @TJHeuvel 会知道最大值吗?
  • 哦,你的意思是执行的最大检查次数?
【解决方案3】:

您不想要最快但最易读的方式。这就是 in_array() (JavaScript: array.indexOf(value) >= 0) 超过 2 或 3 个值。

性能差异可以忽略不计——虽然函数调用和数组创建肯定有一些开销,但与文件访问、数据库访问、网络访问等昂贵的操作相比,这并不重要。所以最终没有人会注意区别。

这是一个简短的benchmark,每个都有 100 万次迭代:

5.4829950332642 - in_array, the array is recreated everytime
2.9785749912262 - in_array, the array is created only once
0.64996600151062 - isset(), the array way created only once and then the values were turned to keys using array_flip()
2.0508298873901 - ||

所以,最快但仍然非常易读的方法是这个。除非您只创建一次 $arr 并使用它多次次,否则没有必要这样做,您可以直接使用 in_array()

$arr = array_flip(array('your', 'list', 'of', 'values'));
if(isset($arr[$value])) ...

如果您确实要求使用 JavaScript(在这种情况下摆脱那些 $ 前缀!),最好的解决方案是使用 Array.indexOf()

['a', 'b', 'c'].indexOf(value) >= 0

然而,并不是所有的浏览器都已经支持Array.indexOf(),所以你可能想使用例如来自Underscore.js的函数:

_.contains(['a', 'b', 'c'], value)

jQuery 也有这样的功能:

$.inArray(value, ['a', 'b', 'c'])

最快的方法是使用对象和in 运算符,但对象定义的可读性不如数组定义:

value in {'a':0, 'b':0, 'c':0}

这里是各种解决方案的 JSPerf 基准测试:http://jsperf.com/inarray-vs-or - 但同样,在大多数情况下,相当大的性能差异可以忽略不计,因为您不会在循环中执行数百万次代码。

【讨论】:

  • 恕我直言,shim Array.indexOf() 比包含另一个完整的 JS 库要好...
  • 如果所有代码都是由您编写而不被视为遗留代码,那确实是一个好主意 - 如果您在某处使用 for(var i in array)(您不应该这样做),扩展 Array.prototype 将打破这些循环。除此之外,OP 已经在使用 jQuery。
  • "所以,最快但仍然非常易读的方法是这个。除非你只创建一次 $arr 并多次使用它,否则不需要这个,你可以简单地留在 in_array() 。”你能更好地解释这部分吗?
  • 只有当实际检查运行很多次并且数组始终相同时,性能差异才相关,即您可以创建一次数组然后重新使用它。
  • 我发现每次创建数组和重用它并没有太大的性能差异......
【解决方案4】:

在大多数语言中,inArray() 是这样实现的:

function inArray(needle, haystack) {
  for (i = 0; i < length; i++) {
    if (haystack[index] == needle) {
      return true;
    }
  }

  return false;
}

如果你要展开那个循环,你最终会这样做

if (haystack[0] == needle) {
  return true;
} 
if (haystack[1] == needle) {
  return true;
}
if (haystack[3] == needle) {
  return true;
}
// and so on

可以压缩成

if (haystack[0] == needle || haystack[2] == needle || … ) {
  return true;
}

不改变幕后发生的事情。


如果您需要反复查找此类内容,我建议您了解地图。而不是

var haystack = ['hello', 'world', 'how', 'is', 'life'];
if (inArray("life", haystack)) {
  // …
}

你会的

var haystack = {'hello' : true, 'world' : true, 'how' : true, 'is' : true, 'life' : true};
if (haystack["life"]) {
  // …
}

需要检查的元素越多,与数组相比,地图的性能就越好。

【讨论】:

  • 如果我需要检查少于 100 个元素,我会感觉到性能提升吗?
  • jsperf.com/map-or-array 表明 10 个元素 inArray() 更快,但 26 个元素已经比 inMap() 慢。请注意,inArray() 的性能与数组中元素的数量以及元素的位置(如果可以找到)相关。另一方面,inMap() 具有相同的性能,无论要比较的项目如何。
  • 好的,所以 chrome 不同意 inArray() 上的 firefox,因为 10 个元素更快。无论如何,你应该得到这张照片……
猜你喜欢
  • 2021-02-27
  • 2017-03-14
  • 2022-01-15
  • 2010-10-21
  • 1970-01-01
  • 2021-08-17
相关资源
最近更新 更多