如何在javascript中检查数组是否包含值?

6qqygrtg  于 2021-09-13  发布在  Java
关注(0)|答案(21)|浏览(400)

找出javascript数组是否包含值的最简洁有效的方法是什么?
这是我知道的唯一方法:

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

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

cs7cruho

cs7cruho1#

先开箱思考一下,如果您多次进行此调用,那么使用关联数组和Map来使用哈希函数进行查找要高效得多。
https://developer.mozilla.org/en-us/docs/web/javascript/reference/global_objects/map

b4wnujal

b4wnujal2#

使用lodash的一些功能。
它简洁、准确,并具有强大的跨平台支持。
被接受的答案甚至不符合要求。
要求:推荐最简洁有效的方法来确定javascript数组是否包含对象。
接受的答复:

$.inArray({'b': 2}, [{'a': 1}, {'b': 2}])
> -1

我的建议是:

_.some([{'a': 1}, {'b': 2}], {'b': 2})
> true

笔记:
$.Inaray w

aoyhnmkz

aoyhnmkz3#

适用于所有现代浏览器的解决方案:

function contains(arr, obj) {
  const stringifiedObj = JSON.stringify(obj); // Cache our object to not call `JSON.stringify` on every iteration
  return arr.some(item => JSON.stringify(item) === stringifiedObj);
}

用法:

contains([{a: 1}, {a: 2}], {a: 1}); // true

ie6+解决方案:

function contains(arr, obj) {
  var stringifiedObj = JSON.stringify(obj)
  return arr.some(function (item) {
    return JSON.stringify(item) === stringifiedObj;
  });
}

// .some polyfill, not needed for IE9+
if (!('some' in Array.prototype)) {
  Array.prototype.some = function (tester, that /*opt*/) {
    for (var i = 0, n = this.length; i < n; i++) {
      if (i in this && tester.call(that, this[i], i, this)) return true;
    } return false;
  };
}

用法:

contains([{a: 1}, {a: 2}], {a: 1}); // true

为什么要使用json.stringify? Array.indexOfArray.includes (以及这里的大多数答案)仅通过参考而不是价值进行比较。

[{a: 1}, {a: 2}].includes({a: 1});
// false, because {a: 1} is a new object

奖金

非优化es6单衬套:

[{a: 1}, {a: 2}].some(item => JSON.stringify(item) === JSON.stringify({a: 1));
// true

注意:如果键的顺序相同,则按值比较对象的效果会更好,因此为了安全起见,您可以先使用如下包对键进行排序:https://www.npmjs.com/package/sort-keys
更新 contains 具有性能优化功能。谢谢你指出这一点。

egmofgnx

egmofgnx4#

我们使用此代码段(用于对象、数组和字符串):

/*
 * @function
 * @name Object.prototype.inArray
 * @description Extend Object prototype within inArray function
 *
 * @param {mix}    needle       - Search-able needle
 * @param {bool}   searchInKey  - Search needle in keys?
 *
 */
Object.defineProperty(Object.prototype, 'inArray',{
    value: function(needle, searchInKey){

        var object = this;

        if( Object.prototype.toString.call(needle) === '[object Object]' || 
            Object.prototype.toString.call(needle) === '[object Array]'){
            needle = JSON.stringify(needle);
        }

        return Object.keys(object).some(function(key){

            var value = object[key];

            if( Object.prototype.toString.call(value) === '[object Object]' || 
                Object.prototype.toString.call(value) === '[object Array]'){
                value = JSON.stringify(value);
            }

            if(searchInKey){
                if(value === needle || key === needle){
                return true;
                }
            }else{
                if(value === needle){
                    return true;
                }
            }
        });
    },
    writable: true,
    configurable: true,
    enumerable: false
});

用法:

var a = {one: "first", two: "second", foo: {three: "third"}};
a.inArray("first");          //true
a.inArray("foo");            //false
a.inArray("foo", true);      //true - search by keys
a.inArray({three: "third"}); //true

var b = ["one", "two", "three", "four", {foo: 'val'}];
b.inArray("one");         //true
b.inArray('foo');         //false
b.inArray({foo: 'val'})   //true
b.inArray("{foo: 'val'}") //false

var c = "String";
c.inArray("S");        //true
c.inArray("s");        //false
c.inArray("2", true);  //true
c.inArray("20", true); //false
pes8fvy9

pes8fvy95#

如果您反复检查数组中是否存在对象,您可能应该查看
通过在数组中执行插入排序(将新对象放在正确的位置),始终保持数组的排序
将更新对象设为删除+排序插入操作,然后
在数据库中使用二进制搜索查找 contains(a, obj) .

chhkpiq4

chhkpiq46#

function inArray(elem,array)
{
    var len = array.length;
    for(var i = 0 ; i < len;i++)
    {
        if(array[i] == elem){return i;}
    }
    return -1;
}

如果找到,则返回数组索引;如果未找到,则返回-1

kupeojn6

kupeojn67#

如果您使用的是javascript 1.6或更高版本(firefox 1.5或更高版本),则可以使用array.indexof。否则,我认为您将得到类似于原始代码的东西。

kknvjkwl

kknvjkwl8#

希望更快的双向 indexOf / lastIndexOf 可供替代的

2015

虽然新方法includes非常好,但目前支持率基本为零。
很长一段时间以来,我一直在考虑替换慢速indexof/lastindexof函数的方法。
我们已经找到了一种有效的方法,看看上面的答案。从那些我选择的 contains @damir zekic发布的函数应该是最快的函数。但它也指出,这些基准是从2008年开始的,因此已经过时。
我也更喜欢 while 结束 for ,但不是因为特定的原因,我用for循环结束了函数的编写。这也可以通过一个 while -- .
我很好奇,如果在执行迭代时检查数组的两侧,迭代是否会慢得多。显然不是,所以这个函数比最受欢迎的函数快两倍左右。显然它也比本地的快。这是在现实环境中进行的,在现实环境中,您永远不知道要搜索的值是在数组的开头还是结尾。
当你知道你刚刚用一个值推送了一个数组时,使用lastindexof可能是最好的解决方案,但是如果你必须遍历大数组,结果可能无处不在,这可能是一个使事情更快的解决方案。
双向索引of/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');

性能测试

http://jsperf.com/bidirectionalindexof
作为测试,我创建了一个包含100k条目的数组。
三个查询:在开始时,在中间和在数组的末尾。
我希望您也会觉得这很有趣,并测试性能。
注意:如您所见,我稍微修改了 contains 函数来反映indexof和lastindexof输出(因此基本上 trueindexfalse 具有 -1 ). 这不应该伤害它。

阵列原型变型

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');

这怎么可能?

我认为在数组中获得反射索引的简单计算非常简单,比实际循环迭代快两倍。
下面是一个复杂的示例,每个迭代执行三次检查,但这只有在计算时间较长的情况下才可能实现,这会导致代码速度减慢。
http://jsperf.com/bidirectionalindexof/2

wi3ka0sx

wi3ka0sx9#

function contains(a, obj) {
    return a.some(function(element){return element == obj;})
}

array.prototype.some()在第5版中添加到ecma-262标准中

ubbxdtey

ubbxdtey10#

我使用以下方法:

Array.prototype.contains = function (v) {
    return this.indexOf(v) > -1;
}

var a = [ 'foo', 'bar' ];

a.contains('foo'); // true
a.contains('fox'); // false
kxxlusnw

kxxlusnw11#

演出

今天是2020.01.07,我在macos highsierra 10.13.6上对chrome v78.0.0、safari v13.0.4和firefox v71.0.0进行测试,测试了15个选定的解决方案。结论
基于 JSON , Set 令人惊讶的是 find (k,n,o)是所有浏览器中速度最慢的
es6 includes (f) 只有在铬上才快速
基于 for (c、d)及 indexOf (g,h)在大小阵列上的所有浏览器上都非常快,因此它们可能是高效解决方案的最佳选择
在循环过程中索引减少的解决方案(b)速度较慢,可能是因为cpu缓存的工作方式。
当搜索的元素位于数组长度的66%位置时,我还对大数组运行了测试,并基于 for (c,d,e)给出了类似的结果(约630次/秒-但safari和firefox上的e比c和d慢10-20%)

结果

细节

我执行了两个测试用例:对于包含10个元素的数组,以及包含1百万个元素的数组。在这两种情况下,我们都将搜索的元素放在数组中间。

let log = (name,f) => console.log(`${name}: 3-${f(arr,'s10')}  's7'-${f(arr,'s7')}  6-${f(arr,6)} 's3'-${f(arr,'s3')}`)

let arr = [1,2,3,4,5,'s6','s7','s8','s9','s10'];
//arr = new Array(1000000).fill(123); arr[500000]=7;

function A(a, val) {
    var i = -1;
    var n = a.length;
    while (i++<n) {
       if (a[i] === val) {
           return true;
       }
    }
    return false;
}

function B(a, val) {
    var i = a.length;
    while (i--) {
       if (a[i] === val) {
           return true;
       }
    }
    return false;
}

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

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

function E(a, val){  
  var n = a.length-1;
  var t = n/2;
  for (var i = 0; i <= t; i++) {
        if (a[i] === val || a[n-i] === val) return true;
  }
  return false;
}

function F(a,val) {
	return a.includes(val);
}

function G(a,val) {
	return a.indexOf(val)>=0;
}

function H(a,val) {
	return !!~a.indexOf(val);
}

function I(a, val) {
  return a.findIndex(x=> x==val)>=0;
}

function J(a,val) {
	return a.some(x=> x===val);
}

function K(a, val) {
  const s = JSON.stringify(val);
  return a.some(x => JSON.stringify(x) === s);
}

function L(a,val) {
	return !a.every(x=> x!==val);
}

function M(a, val) {
  return !!a.find(x=> x==val);
}

function N(a,val) {
	return a.filter(x=>x===val).length > 0;
}

function O(a, val) {
  return new Set(a).has(val);
}

log('A',A);
log('B',B);
log('C',C);
log('D',D);
log('E',E);
log('F',F);
log('G',G);
log('H',H);
log('I',I);
log('J',J);
log('K',K);
log('L',L);
log('M',M);
log('N',N);
log('O',O);
This shippet only presents functions used in performance tests - it not perform tests itself!

小数组-10个元素
您可以在这里的机器上执行测试

阵列大-1.000.000个元素
您可以在这里的机器上执行测试

9q78igpj

9q78igpj12#

一艘班轮:

function contains(arr, x) {
    return arr.filter(function(elem) { return elem == x }).length > 0;
}
thtygnil

thtygnil13#

扩展javascript Array 对象是一个非常糟糕的主意,因为您将新属性(您的自定义方法)引入到 for-in 可以中断现有脚本的循环。几年前,原型库的作者不得不重新设计他们的库实现,以删除这种东西。
如果您不需要担心与页面上运行的其他javascript的兼容性,那么就去做吧,否则,我建议使用更笨拙但更安全的独立函数解决方案。

yb3bgrhw

yb3bgrhw14#

使用:

function isInArray(array, search)
{
    return array.indexOf(search) >= 0;
}

// Usage
if(isInArray(my_array, "my_value"))
{
    //...
}
ebdffaop

ebdffaop15#

下面是与javascript 1.6兼容的 Array.indexOf :

if (!Array.indexOf) {
    Array.indexOf = [].indexOf ?
        function(arr, obj, from) {
            return arr.indexOf(obj, from);
        } :
        function(arr, obj, from) { // (for IE6)
            var l = arr.length,
                i = from ? parseInt((1 * from) + (from < 0 ? l : 0), 10) : 0;
            i = i < 0 ? 0 : i;
            for (; i < l; i++) {
                if (i in arr && arr[i] === obj) {
                    return i;
                }
            }
            return -1;
        };
}

相关问题