找出JavaScript数组是否包含值的最简洁有效的方法是什么?

这是我知道的唯一方法:

function contains(a, obj) {
    for (var i = 0; i < a.length; i++) {
        if (a[i] === obj) {
            return true;
        }
    }
    return false;
}

有没有更好、更简洁的方法来实现这一点?

这与堆栈溢出问题密切相关。在JavaScript数组中查找项目的最佳方法是什么?它解决了使用indexOf查找数组中的对象的问题。


当前回答

我建议使用下划线库,因为它返回值,并且支持所有浏览器。

下芯js

 var findValue = _.find(array, function(item) {
    return item.id == obj.id;
 });

其他回答

如果你使用的是JavaScript 1.6或更高版本(Firefox 1.5或更高),你可以使用Array.indexOf。

上面的答案假设是基元类型,但如果您想知道数组是否包含具有某种特征的对象,array.protocol.some()是一个很好的解决方案:

const items = [ {a: '1'}, {a: '2'}, {a: '3'} ]

items.some(item => item.a === '3')  // returns true
items.some(item => item.a === '4')  // returns false

它的好处是,一旦找到元素,迭代就被中止,从而避免了不必要的迭代周期。

此外,它很适合if语句,因为它返回布尔值:

if (items.some(item => item.a === '3')) {
  // do something
}

*正如jamess在评论中指出的那样,在2018年9月回答这个问题时,Array.protocol.some()是完全支持的:caniuse.com支持表

复杂性O(n/2)

您可以使用任何库函数,但我使用的是核心JavaScript。如果返回true,我们首先搜索中间的元素,否则我们同时从左到中和从右到中搜索数组中的元素。因此,它将具有O(n/2)复杂性。并且它将返回true或false,指示它是否存在

let isExist = (arr, element)=> {
  let index = -1;
  if ((arr.length % 2 != 0) && arr[(arr.length-1)/2]===element) {
    index = 1;
    return true;
  }
  for(let i=0; i<Math.ceil(arr.length-1/2); i++){
    if (arr[i]===element || (arr[arr.length-i]===element)) {
      index = i;
      break;
    }
  }
  return (index<0)? false : true;
}



let array = ['apple', 'ball', 'cat', 'dog', 'egg']

console.log(isExist(array, 'yellow'));
//Result false because yellow doesn't exist in array
console.log(isExist(array, 'cat'));
//Result true because yellow exist in array

使用idnexOf()是一个很好的解决方案,但您应该隐藏嵌入的实现indexOf(()函数,该函数使用~运算符返回-1:

function include(arr,obj) { 
    return !!(~arr.indexOf(obj)); 
} 

希望更快的双向indexOf/lastIndexOf替代方案

2015

虽然新方法包含的内容非常好,但目前支持基本为零。

很长时间以来,我一直在想一种方法来替换缓慢的indexOf/lastIndexOf函数。

已经找到了一种表演方式,看看最热门的答案。我选择了@Damir Zekic发布的contains函数,这应该是最快的函数。但它也指出,基准是2008年的,因此已经过时。

我也更喜欢while而不是for,但不是出于特定原因,我用for循环结束了函数的编写。这也可以在一段时间内完成。

我很好奇,如果我在执行时检查数组的两侧,迭代是否会慢得多。显然没有,所以这个函数比排名靠前的函数快两倍左右。显然,它也比本地的更快。这是在一个真实的环境中,您永远不知道所搜索的值是在数组的开头还是结尾。

当你知道你只是用一个值推送一个数组时,使用lastIndexOf可能是最好的解决方案,但如果你必须遍历大数组,结果可能无处不在,这可能是一个让事情更快的可靠解决方案。

双向indexOf/lastIndexOf

function bidirectionalIndexOf(a, b, c, d, e){
  for(c=a.length,d=c*1; c--; ){
    if(a[c]==b) return c; //or this[c]===b
    if(a[e=d-1-c]==b) return e; //or a[e=d-1-c]===b
  }
  return -1
}

//Usage
bidirectionalIndexOf(array,'value');

性能测试

https://jsbench.me/7el1b8dj80

作为测试,我创建了一个包含100k个条目的数组。

三个查询:在数组的开头、中间和结尾。

我希望你也觉得这很有趣,并测试一下性能。

注意:正如您所看到的,我稍微修改了contains函数,以反映indexOf和lastIndexOf输出(因此,索引基本为true,-1为false)。这不应该伤害它。

阵列原型变体

Object.defineProperty(Array.prototype,'bidirectionalIndexOf',{value:function(b,c,d,e){
  for(c=this.length,d=c*1; c--; ){
    if(this[c]==b) return c; //or this[c]===b
    if(this[e=d-1-c] == b) return e; //or this[e=d-1-c]===b
  }
  return -1
},writable:false, enumerable:false});

// Usage
array.bidirectionalIndexOf('value');

该函数也可以很容易地修改为返回true或false,甚至返回对象、字符串或任何其他值。

下面是while变体:

function bidirectionalIndexOf(a, b, c, d){
  c=a.length; d=c-1;
  while(c--){
    if(b===a[c]) return c;
    if(b===a[d-c]) return d-c;
  }
  return c
}

// Usage
bidirectionalIndexOf(array,'value');

这怎么可能?

我认为,获取数组中反射索引的简单计算非常简单,比实际循环迭代快两倍。

这里有一个复杂的例子,每次迭代进行三次检查,但这仅在计算时间较长时才有可能,因为计算时间较长会导致代码速度减慢。

https://web.archive.org/web/20151019160219/http://jsperf.com/bidirectionalindexof/2