查找项目是不是在 JavaScript 数组中的最佳方法? [复制]

Posted

技术标签:

【中文标题】查找项目是不是在 JavaScript 数组中的最佳方法? [复制]【英文标题】:Best way to find if an item is in a JavaScript array? [duplicate]查找项目是否在 JavaScript 数组中的最佳方法? [复制] 【发布时间】:2010-09-13 17:13:48 【问题描述】:

判断一个对象是否在数组中的最好方法是什么?

这是我知道的最好的方法:

function include(arr, obj) 
  for (var i = 0; i < arr.length; i++) 
    if (arr[i] == obj) return true;
  


console.log(include([1, 2, 3, 4], 3)); // true
console.log(include([1, 2, 3, 4], 6)); // undefined

【问题讨论】:

见:***.com/a/25765186/1320932 两件事:1.) 对于一个不修改任何状态的函数来说,'include' 是一个非常糟糕的名字。对于只返回布尔值的函数来说尤其糟糕。 2.) 您需要添加“return(false);”在函数结束之前。 从 ECMAScript 2016 开始,您可以使用 Array.prototype.includes 函数:myArray.includes(3); // 是的 在 ES6 中,您可以执行类似 arr.find(lamda function) 的操作,例如:[1, 2, 3,4,5].find(x => x == 3)。如果找到元素,则返回否则返回未定义 arr.some(element => element === obj); some 是最好的方法,因为当它找到一个项目然后打破循环时。 【参考方案1】:

从 ECMAScript 2016 开始,您可以使用 includes()

arr.includes(obj);

如果您想支持 IE 或其他旧版浏览器:

function include(arr,obj) 
    return (arr.indexOf(obj) != -1);

编辑: 不过,这不适用于 IE6、7 或 8。如果它不存在,最好的解决方法是自己定义它:

    Mozilla's (ECMA-262) 版本:

       if (!Array.prototype.indexOf)
       
    
            Array.prototype.indexOf = function(searchElement /*, fromIndex */)
    
         
    
    
         "use strict";
    
         if (this === void 0 || this === null)
           throw new TypeError();
    
         var t = Object(this);
         var len = t.length >>> 0;
         if (len === 0)
           return -1;
    
         var n = 0;
         if (arguments.length > 0)
         
           n = Number(arguments[1]);
           if (n !== n)
             n = 0;
           else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0))
             n = (n > 0 || -1) * Math.floor(Math.abs(n));
         
    
         if (n >= len)
           return -1;
    
         var k = n >= 0
               ? n
               : Math.max(len - Math.abs(n), 0);
    
         for (; k < len; k++)
         
           if (k in t && t[k] === searchElement)
             return k;
         
         return -1;
       ;
    
     
    

    Daniel James的版本:

     if (!Array.prototype.indexOf) 
       Array.prototype.indexOf = function (obj, fromIndex) 
         if (fromIndex == null) 
             fromIndex = 0;
          else if (fromIndex < 0) 
             fromIndex = Math.max(0, this.length + fromIndex);
         
         for (var i = fromIndex, j = this.length; i < j; i++) 
             if (this[i] === obj)
                 return i;
         
         return -1;
       ;
     
    

    roosteronacid的版本:

     Array.prototype.hasObject = (
       !Array.indexOf ? function (o)
       
         var l = this.length + 1;
         while (l -= 1)
         
             if (this[l - 1] === o)
             
                 return true;
             
         
         return false;
        : function (o)
       
         return (this.indexOf(o) !== -1);
       
     );
    

【讨论】:

我很好奇为什么您的 Mozilla 功能版本与您链接的网站如此不同。是你自己修改的还是只是旧版本之类的? @Shenjoku:“2008 年 9 月 27 日 15:45 回答” 嗯,这就是我的答案哈哈。我不能仅通过查看 mozilla 网站来判断是否有旧版本,所以我不确定。不重要,只是好奇。无论如何,这仍然很有帮助,因此您会获得支持;) @Vinko Vrsalovic 是的,这是一个很好的解决方案,但是您应该隐藏嵌入式实现 indexOf() 函数,它使用 ~ 运算符返回 -1: function include(arr,obj) return !!(~ arr.indexOf(obj)) ; 但是,自从indexOf什么时候兼容IE,因为我发现它兼容IE w3schools.com/jsref/jsref_indexof.asp【参考方案2】:

如果你使用的是 jQuery:

$.inArray(5 + 5, [ "8", "9", "10", 10 + "" ]);

欲了解更多信息:http://api.jquery.com/jQuery.inArray/

【讨论】:

请注意,“inArray”是用词不当,因为它不返回布尔值 - 它返回找到的第一个元素的索引。因此,如果您要检查元素是否存在,您应该使用if (-1 != $.inArray(...)) ... 有帮助,但我认为这不是一个合适的答案。在我看来,这个问题被标记为“javascript”,表示“香草”。 :)【参考方案3】:

首先,在 JavaScript 中为还没有 indexOf 的浏览器实现 indexOf。例如,请参阅 Erik Arvidsson's array extras(也称为 associated blog post)。然后您可以使用indexOf,而无需担心浏览器支持。这是他的indexOf 实现的略微优化版本:

if (!Array.prototype.indexOf) 
    Array.prototype.indexOf = function (obj, fromIndex) 
        if (fromIndex == null) 
            fromIndex = 0;
         else if (fromIndex < 0) 
            fromIndex = Math.max(0, this.length + fromIndex);
        
        for (var i = fromIndex, j = this.length; i < j; i++) 
            if (this[i] === obj)
                return i;
        
        return -1;
    ;

它已更改为存储长度,因此不需要每次迭代都查找它。但差别不是很大。不太通用的函数可能会更快:

var include = Array.prototype.indexOf ?
    function(arr, obj)  return arr.indexOf(obj) !== -1;  :
    function(arr, obj) 
        for(var i = -1, j = arr.length; ++i < j;)
            if(arr[i] === obj) return true;
        return false;
    ;

我更喜欢使用标准功能,并在真正需要时保留这种微优化。但是,如果您热衷于微优化,我将与 cmets 中的公鸡酮酸相关的 benchmarks 改编为 benchmark searching in arrays。虽然它们非常粗略,但完整的调查将测试具有不同类型、不同长度的数组并找到出现在不同位置的对象。

【讨论】:

您链接到的代码示例在大型数组上运行缓慢。请参阅我的 hasItem() 函数实现示例中的 cmets。 看看这些基准测试:blogs.sun.com/greimer/resource/loop-test.htm For 循环很慢。但我猜基准测试中使用的数组非常庞大:) blogs.sun.com/greimer/resource/loop-test.html 我同意。我也很务实。但在优化语言基础的情况下,我认为实现功能尽可能提高性能是很好的设计。 使用 mozilla Array.indexOf polyfill:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…【参考方案4】:

如果数组未排序,实际上没有更好的方法(除了使用上面提到的 indexOf,我认为这相当于同一件事)。如果数组已排序,则可以进行二进制搜索,其工作原理如下:

    选择数组的中间元素。 您要查找的元素是否比您选择的元素大?如果是这样,您已经消除了数组的下半部分。如果不是,您已经淘汰了上半部分。 选择数组剩余一半的中间元素,并按照步骤 2 继续,消除剩余数组的一半。最终,您要么找到您的元素,要么没有剩余的数组可供查看。

二分查找的运行时间与数组长度的对数成正比,因此它比查看每个单独的元素要快得多。

【讨论】:

您可能应该提到,这种方法在大型排序数组上比小型数组更快。 为什么在较小的阵列上会变慢? @vidstige:他的意思是它可以很好地扩展,但对于小输入来说不一定是最快的。 这在 O(lg n) 中运行,而不是 O(n),后者更具可扩展性【参考方案5】:

[ ].has(obj)

假设.indexOf() 已实现

Object.defineProperty( Array.prototype,'has',

    value:function(o, flag)
    if (flag === undefined) 
        return this.indexOf(o) !== -1;
     else    // only for raw js object
        for(var v in this) 
            if( JSON.stringify(this[v]) === JSON.stringify(o)) return true;
        
        return false;                       
    ,
    // writable:false,
    // enumerable:false
)

!!!不要创建Array.prototype.has=function()...,因为你会在每个数组中添加一个可枚举的元素,而 js 会被破坏。

//use like          
[22 ,'a', prop:'x'].has(12) // false
["a","b"].has("a") //  true

[1,a:1].has(a:1,1) // true
[1,a:1].has(a:1) // false

使用第二个参数(标志)强制按值而不是参考进行比较

比较原始对象

[o1].has(o2,true) // true if every level value is same

【讨论】:

【参考方案6】:

这取决于你的目的。如果您为 Web 编程,请避免使用 indexOf,Internet Explorer 6 不支持它(其中很多仍在使用!),或者有条件地使用:

if (yourArray.indexOf !== undefined) result = yourArray.indexOf(target);
else result = customSlowerSearch(yourArray, target);

indexOf 可能是用本机代码编码的,所以它比你在 JavaScript 中可以做的任何事情都要快(如果数组合适,二进制搜索/二分法除外)。 注意:这是一个品味问题,但我会在你的例程结束时做一个return false;,以返回一个真正的布尔值......

【讨论】:

哈哈...我觉得现在还有一个 IE6 客户端... 不应该在***页面中出现“截至 2008 年”,这样人们就知道这个声明肯定已经过时了 @allan.simon 查看答案底部的图标(和统计信息)。就在上面,有“2008 年 9 月 27 日 16:28 回答”。它被称为日期,习惯于 Stack Overflow 的人们会在查看这些日期时持怀疑态度...也就是说,我当地的公共图书馆仍然在他们的计算机上安装了 IE6! (但幸运的是,有人安装了 Chrome!)【参考方案7】:

这里有一些元知识 - 如果你想知道可以用数组做什么,请查看文档 - 这是 Mozilla 的数组页面

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

您会在此处看到对 indexOf 的引用,它是在 Javascript 1.6 中添加的

【讨论】:

包含有关 Javascript 1.8 及更高版本信息的手册的奇怪 URL! :) 这不包括作者询问的对象数组 @VinkoVrsalovic:网址已更改为developer.mozilla.org/en-US/docs/JavaScript/Reference/…【参考方案8】:

这里详细介绍了一种检查对象是否为 javascript 中的数组的可靠方法:

这里有两个来自xa.js 框架的函数,我将它们附加到utils = “容器”。这些应该可以帮助您正确检测数组。

var utils = ;

/**
 * utils.isArray
 *
 * Best guess if object is an array.
 */
utils.isArray = function(obj) 
     // do an instanceof check first
     if (obj instanceof Array) 
         return true;
     
     // then check for obvious falses
     if (typeof obj !== 'object') 
         return false;
     
     if (utils.type(obj) === 'array') 
         return true;
     
     return false;
 ;

/**
 * utils.type
 *
 * Attempt to ascertain actual object type.
 */
utils.type = function(obj) 
    if (obj === null || typeof obj === 'undefined') 
        return String (obj);
    
    return Object.prototype.toString.call(obj)
        .replace(/\[object ([a-zA-Z]+)\]/, '$1').toLowerCase();
;

如果你想检查一个对象是否在一个数组中,我也会包含这个代码:

/**
 * Adding hasOwnProperty method if needed.
 */
if (typeof Object.prototype.hasOwnProperty !== 'function') 
    Object.prototype.hasOwnProperty = function (prop) 
        var type = utils.type(this);
        type = type.charAt(0).toUpperCase() + type.substr(1);
        return this[prop] !== undefined
            && this[prop] !== window[type].prototype[prop];
    ;

最后是这个 in_array 函数:

function in_array (needle, haystack, strict) 
    var key;

    if (strict) 
        for (key in haystack) 
            if (!haystack.hasOwnProperty[key]) continue;

            if (haystack[key] === needle) 
                return true;
            
        
     else 
        for (key in haystack) 
            if (!haystack.hasOwnProperty[key]) continue;

            if (haystack[key] == needle) 
                return true;
            
        
    

    return false;

【讨论】:

虽然这在理论上可以回答这个问题,it would be preferable 在此处包含答案的基本部分,并提供链接以供参考。此外,当您一次复制/粘贴相同的仅链接回答几个非常老的问题时,它看起来就像垃圾邮件。 对不起比尔,我真的不是故意让它看起来像垃圾邮件,我只是想更新一些关于这个话题的老问题。我在这里编辑了帖子以包含实际答案,而不是链接。 @Bill,实际上重新阅读了这个问题,这甚至根本没有回答。我一定是搞错了。

以上是关于查找项目是不是在 JavaScript 数组中的最佳方法? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

Javascript算法在数组中查找不在另一个数组中的元素

如何检查数组是不是包含 JavaScript 中的值?

如何检查数组是不是包含 JavaScript 中的值?

在Javascript中更新对象数组中的键的最有效方法是啥? [复制]

javascript中的大型数组是不是有项目限制

使用 Jquery Each 在 Javascript 对象和数组中查找匹配项