检查数组中是否存在一个元素

778

我现在正在使用的函数来检查这个问题如下:

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

它有效。有更好的方法吗?


1
看起来对我来说没问题。当然,如果你的数组已经排序了,你可以使用二分查找。或者,如果数组中每个值都是唯一的,你可以使用基于映射的方法。 - aroth
4
“==” 运算符?您真的想显式地允许类型强制转换吗?当然不是。因此,应改用“===”运算符。 - Šime Vidas
在循环之前声明 count 是明智的选择。你也可以用 for(var i=haystack.length; i--;) 替换那两行代码。 - Greg Perham
对于数字,我们也可以使用 in 运算符(例如 (5 in array))。它可能比其他选项更快,但不适用于字符串、对象或任何其他非数字。 - Yuval A.
9个回答

1335

ECMAScript 2016包含了一个数组方法includes(),专门解决了这个问题,因此现在是首选的方法。

[1, 2, 3].includes(2);     // true
[1, 2, 3].includes(4);     // false
[1, 2, 3].includes(1, 2);  // false (second parameter is the index position in this array at which to begin searching)

截至2018年7月,这个已经在几乎所有主要的浏览器中实现了,如果你需要支持旧的浏览器,可以使用polyfill

编辑:请注意,如果数组中的项是对象,则此函数将返回false。这是因为在JavaScript中,相似的对象是两个不同的对象。


31
什么是“polyfill”? - nirvanaswap
53
@nirvanaswap 一个 polyfill 是一个脚本,你可以使用它来确保任何浏览器都有你正在使用的某个东西的实现。在这种情况下,你需要增加一个脚本,检查 if ("includes" in Array.prototype) 是否存在,如果不存在,则实现它(例如使用 Benny 的答案 中的解决方案)。MDN 文档(也包含在此答案中的链接中)实际上已经为你提供了一个 polyfill。 - FireSBurnsmuP
我使用以下代码,运行良好。并且不会推送重复的值。非常感谢!this.state.UpdatedfriendList.includes(s.valueKey) === false ? this.state.UpdatedfriendList.push(s.valueKey) : ''; - Pankaj
1
@PrithiviRaj 这将是线性时间,因此性能影响将与数组大小成正比。 - Alister
2
使用广泛支持的 myArray.indexOf(myVal) > -1 是同样的事情,但更安全。 - vinsa
显示剩余6条评论

488

代码:

function isInArray(value, array) {
  return array.indexOf(value) > -1;
}

执行:

isInArray(1, [1,2,3]); // true

更新(2017):

在遵循ECMAScript 2016(ES7)标准的现代浏览器中,您可以使用函数Array.prototype.includes,这使得检查数组中是否存在项变得更加容易:

const array = [1, 2, 3];
const value = 1;
const isInArray = array.includes(value);
console.log(isInArray); // true


10
非常抱歉,您提供的内容无法翻译。这个字符串似乎是一个逻辑表达式,但它缺少一些关键信息,因此无法正确解释其含义。请提供更多上下文或详细说明所需的翻译类型,以便我能够更好地为您提供服务。 - Francisc
4
indexOf 在 IE 浏览器中运行时存在问题。 - user2598812
23
@totaldesign 你说它工作得“不仔细”,是指它在IE中工作得“粗心大意”吗? :D - Sнаđошƒаӽ
适用于 Node 4.4.7。 - Jerico Sandhorn
1
据我所知,ES2016(其中包括数组的includes方法)是ECMAScript的第七版。第六版是ES 2015,不包含“includes”。请纠正。 https://en.wikipedia.org/wiki/ECMAScript#7th_Edition_-_ECMAScript_2016 - Juergen
@Juergen 谢谢您的提示!我已更新内容。 - Benny Code

103

只需使用indexOf即可:

haystack.indexOf(needle) >= 0

如果您想支持旧版的Internet Explorer(< IE9),则需要通过一个解决方案来包含您当前的代码。

除非您的列表已经排序,否则您需要将每个值与查找项进行比较。因此,您的解决方案和indexOf方法都需要执行平均 n/2 次比较。然而,由于indexOf是内置方法,它可能使用额外的优化,实际上会稍微快一些。请注意,除非您的应用程序需要极度频繁地搜索列表(例如每秒1000次)或列表非常庞大(例如100k条目),否则速度差异不会很大。


Array.prototype.indexOf 在 IE8 中未被实现。 - Šime Vidas
不支持IE浏览器(可能只有9)https://dev59.com/MnI-5IYBdhLWcg3wpqMK - Shadow The Spring Wizard
3
这个页面上已经有提到,但作为答案的一部分也值得提及:indexOf是JavaScript的一个相对较新的特性,在IE 9.0之前的版本中不受支持。另外值得注意的是,indexOf仍然具有O(n)的时间复杂度,所以如果OP在速度/性能方面更希望有所改善,这并不能真正做到,只是代码更短而已。 - aroth
@Tomalak Geret'kal 没错,虽然这个参数非常简单。为了防止OP所说的“更好”的意思是性能方面的,我添加了一个关于性能的段落。 - phihag
嗨,我主要是指速度方面更好。代码长度很重要,但速度比长度更重要。该数组未排序,而是在检查时创建的。如果一个字符串值不在数组中,则会添加它。 - Francisc
4
你可以尝试一种基于地图的方法。这样,你的inArray()实现可能会非常简单,只需要return haystack[needle] != undefined;即可。 - aroth

49

我在谷歌浏览器52版本上进行了多次基准测试,但随意将其复制粘贴到任何其他浏览器的控制台中。


大约1500毫秒,包括(使用polyfill时大约2700毫秒)

var array = [0,1,2,3,4,5,6,7,8,9]; 
var result = 0;

var start = new Date().getTime();
for(var i = 0; i < 10000000; i++)
{
  if(array.includes("test") === true){ result++; }
}
console.log(new Date().getTime() - start);

~ 1050毫秒,indexOf

var array = [0,1,2,3,4,5,6,7,8,9]; 
var result = 0;

var start = new Date().getTime();
for(var i = 0; i < 10000000; i++)
{
  if(array.indexOf("test") > -1){ result++; }
}
console.log(new Date().getTime() - start);

~ 650毫秒,自定义函数

function inArray(target, array)
{

/* Caching array.length doesn't increase the performance of the for loop on V8 (and probably on most of other major engines) */

  for(var i = 0; i < array.length; i++) 
  {
    if(array[i] === target)
    {
      return true;
    }
  }

  return false; 
}

var array = [0,1,2,3,4,5,6,7,8,9]; 
var result = 0;

var start = new Date().getTime();
for(var i = 0; i < 10000000; i++)
{
  if(inArray("test", array) === true){ result++; }
}
console.log(new Date().getTime() - start);

8
我的笔记本电脑上原本的数值是 ~ 950 / 750 / 650。我只是把数组改成了 ['df', 'ff', 2, 3, 4, 5, 6, 333, 8, 9],然后得到的结果是 ~ 950 / 900 / 3150。 - Max Lipsky
130-160 / 120-160 / 110-130 但是 some,正如我所预期的,如果 (array.some(i => i>2)),速度会快两倍。结果会增加一次。大约需要50-90毫秒。 - undefined

27

一行代码...会返回true或false

!!(arr.indexOf("val")+1)

22
因为每个人都喜欢波浪号,所以这里使用了波浪号:!!~arr.indexOf("val")。该代码的含义是查找数组 arr 中是否包含值为 "val" 的元素,如果包含则返回 true,否则返回 false - Samie Bencherif
1
或者只需使用 ~arr.indexOf("val")。0 = 假值,其他数字 = 真值 - Viliami
3
"uhhh,0应该是true,因为它在数组中被发现作为第一个元素?" - Pysis
如果你需要考虑IE11的话,最佳解决方案。 - Andrew Howard

21

您可以使用 indexOf,但在最新版本的Internet Explorer中可能无法正常工作。 代码:

function isInArray(value, array) {
  return array.indexOf(value) > -1;
}

执行:

isInArray(1, [1,2,3]); // true

我建议您使用以下代码:

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

12

自ECMAScript6起,可以使用Set:

var myArray = ['A', 'B', 'C'];
var mySet = new Set(myArray);
var hasB = mySet.has('B'); // true
var hasZ = mySet.has('Z'); // false

10
你可以使用underscore.js库中的_contains函数来实现这一点:

你可以使用_contains函数从underscore.js库中实现这个功能:

if (_.contains(haystack, needle)) {
  console.log("Needle found.");
};

3
这只是为了使用underscore库吗? - Rahul Desai
6
并非必须如此,因为开发者可能已经在应用程序中使用Underscore来实现其他功能。 使用Underscore只是众多解决方案之一。 - Chris Alley

4
在lodash中,您可以使用_.includes(也是_.contains的别名)搜索整个数组。
您可以搜索整个数组:
_.includes([1, 2, 3], 1); // true

你可以从起始索引开始搜索数组:
_.includes([1, 2, 3], 1, 1);  // false (begins search at index 1)

搜索字符串:

_.includes('pebbles', 'eb');  // true (string contains eb)

也适用于检查简单的对象数组:

_.includes({ 'user': 'fred', 'age': 40 }, 'fred');    // true
_.includes({ 'user': 'fred', 'age': false }, false);  // true

关于最后一个例子需要注意的是,它适用于字符串、数字和布尔类型等基本类型,但无法搜索数组或对象。

_.includes({ 'user': 'fred', 'age': {} }, {});   // false
_.includes({ 'user': [1,2,3], 'age': {} }, 3);   // false

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接