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

这是我知道的唯一方法:

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

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

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


当前回答

您也可以使用此技巧:

var arrayContains = function(object) {
  return (serverList.filter(function(currentObject) {
    if (currentObject === object) {
      return currentObject
    }
    else {
      return false;
    }
  }).length > 0) ? true : false
}

其他回答

而array.indexOf(x)=-1是实现这一点的最简洁的方法(并且已经被非Internet Explorer浏览器支持了十多年……),它不是O(1),而是O(N),这很可怕。如果您的数组不会改变,您可以将数组转换为哈希表,然后执行表[x]==未定义或==未定义:

Array.prototype.toTable = function() {
    var t = {};
    this.forEach(function(x){t[x]=true});
    return t;
}

演示:

var toRemove = [2,4].toTable();
[1,2,3,4,5].filter(function(x){return toRemove[x]===undefined})

(不幸的是,虽然您可以创建Array.prototype.contains来“冻结”数组并将哈希表存储在this._cache中,但如果您选择稍后编辑数组,则会产生错误的结果。与Python不同,JavaScript没有足够的钩子来保持这种状态。)

想一想,如果您多次调用此调用,那么使用关联数组Map使用哈希函数进行查找会更有效。

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map

我查看了提交的答案,发现只有通过引用搜索对象时,这些答案才适用。具有参考对象比较的简单线性搜索。

但是,假设您没有对象的引用,如何在数组中找到正确的对象?您必须对每个对象进行线性和深度比较。想象一下,如果列表太大,并且其中的对象非常大,包含大量文本。随着阵列中元素的数量和大小,性能急剧下降。

您可以将对象字符串化并将其放入本机哈希表中,但这样您就有了记住这些键的数据冗余,因为JavaScript将它们保存为“for i in obj”,您只需要检查对象是否存在,也就是说,您拥有该键。

我考虑了一段时间来构建一个JSON模式验证器,我为本地哈希表设计了一个简单的包装器,类似于唯一的哈希表实现,但一些优化异常我留给本地哈希表处理。它只需要性能基准。。。所有详细信息和代码都可以在我的博客上找到:http://stamat.wordpress.com/javascript-quickly-find-very-large-objects-in-a-large-array/我将很快发布基准结果。

完整的解决方案如下所示:

var a = {'a':1,
 'b':{'c':[1,2,[3,45],4,5],
 'd':{'q':1, 'b':{'q':1, 'b':8},'c':4},
 'u':'lol'},
 'e':2};

 var b = {'a':1, 
 'b':{'c':[2,3,[1]],
 'd':{'q':3,'b':{'b':3}}},
 'e':2};

 var c = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.";

 var hc = new HashCache([{a:3, b:2, c:5}, {a:15, b:2, c:'foo'}]); //init

 hc.put({a:1, b:1});
 hc.put({b:1, a:1});
 hc.put(true);
 hc.put('true');
 hc.put(a);
 hc.put(c);
 hc.put(d);
 console.log(hc.exists('true'));
 console.log(hc.exists(a));
 console.log(hc.exists(c));
 console.log(hc.exists({b:1, a:1}));
 hc.remove(a);
 console.log(hc.exists(c));

它有一个参数:对象的数组数。数组中的每个对象都有两个由x和y表示的整数财产。该函数必须返回数组中满足numbers.x==numbers.y的所有此类对象的计数

var数=〔{x:1,y:1},{x:2,y:3},{x:3,y:3},{x:3,y:4},{x:4,y:5}];变量计数=0;var n=数字长度;对于(变量i=0;i<n;i++){如果(数字[i].x==数字[i].y){count+=1;}}警报(计数);

希望更快的双向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