【问题标题】:indexOf method in an object array?对象数组中的 indexOf 方法?
【发布时间】:2012-01-29 21:21:35
【问题描述】:

获取包含对象的数组的索引的最佳方法是什么?

想象一下这个场景:

var hello = {
    hello: 'world',
    foo: 'bar'
};
var qaz = {
    hello: 'stevie',
    foo: 'baz'
}

var myArray = [];
myArray.push(hello,qaz);

现在我想要indexOf 对象,其hello 属性为'stevie',在本例中为1

我是 JavaScript 的新手,我不知道是否有简单的方法,或者我是否应该构建自己的函数来做到这一点。

【问题讨论】:

  • 你想合并helloqaz这两个对象吗?
  • 不,我没有。我想要一个数组中的对象列表。
  • 啊好吧!你想知道整个对象在数组中的位置,它有一个定义的属性。
  • 我找到了一个非常简单的函数来解决这个 SO 答案的确切问题:var elementPos = array.map(function(x) {return x.id; }).indexOf(idYourAreLookingFor); var objectFound = array[elementPos]; [link] (stackoverflow.com/a/16100446/1937255)
  • ES6 Array.indexOf 比公认的答案更好(如果 ES6 适合您) - 请参阅下面的完整示例

标签: javascript


【解决方案1】:

我认为您可以使用map 函数在一行中解决它:

pos = myArray.map(function(e) { return e.hello; }).indexOf('stevie');

【讨论】:

  • 老实说,这应该是公认的答案。现在大多数浏览器都支持Array.prototype.map()
  • IE8 不支持,但如果这不是问题,这是最好的解决方案。
  • 嗯... Array.prototype.map() 创建一个包含映射项的全新数组难道不值得注意吗?那么,如果您有一个包含 1000 个元素的数组,那么您首先创建了一个包含 1000 个元素的 another 数组,然后再搜索它?我认为看看这种方法与简单 for 循环的性能对比是值得的。尤其是当您在资源有限的移动平台上运行时。
  • @Doug 尽管您关于性能的观点确实是正确的,但在他们正确的头脑中,谁会用七行代码替换几乎定义为 IO/网络绑定的应用程序,直到他们分析瓶颈?
  • 技术上一个缩小的 js 文件也是一行 ;D
【解决方案2】:

Array.prototype.findIndex 支持除 IE(非边缘)以外的所有浏览器。但是提供的polyfill 很好。

var indexOfStevie = myArray.findIndex(i => i.hello === "stevie");

使用地图的解决方案是可以的。但是您每次搜索都在遍历整个数组。这只是 findIndex 最坏的情况,一旦找到匹配项就会停止迭代。


没有真正简洁的方法 (当开发者不得不担心 IE8 时),但这里有一个常见的解决方案:
var searchTerm = "stevie",
    index = -1;
for(var i = 0, len = myArray.length; i < len; i++) {
    if (myArray[i].hello === searchTerm) {
        index = i;
        break;
    }
}

或作为一个函数:

function arrayObjectIndexOf(myArray, searchTerm, property) {
    for(var i = 0, len = myArray.length; i < len; i++) {
        if (myArray[i][property] === searchTerm) return i;
    }
    return -1;
}
arrayObjectIndexOf(arr, "stevie", "hello"); // 1

只是一些注释:

  1. 不要在数组上使用 for...in 循环
  2. 一旦找到“针”,请务必跳出循环或退出函数
  3. 注意对象相等性

例如,

var a = {obj: 0};
var b = [a];
b.indexOf({obj: 0}); // -1 not found

【讨论】:

  • 该函数的搜索词比较错误,因为它应该是 searchTerm :)
  • 多次出现
  • @SteveBennett 这是一个性能优化版本;数组的长度只需确定一次(当初始化 for 循环的变量时)。在您的情况下,每次迭代都会重新检查长度。另请参阅 stackoverflow.com/questions/5349425/…stackoverflow.com/questions/8452317/… 但是,如果性能不高,那并不重要。
  • 很好的答案,但我做了一些性能基准测试(参见jsperf.com/find-index-of-object-in-array-by-contents),发现这里提到的基于函数的答案似乎是第二好的答案。正如my answer 中提到的那样,唯一更高效的是将其放入原型中,而不仅仅是一个函数。
  • Polyfill 链接已失效!
【解决方案3】:

在 ES2015 中,这很容易:

myArray.map(x => x.hello).indexOf('stevie')

或者,对于较大的数组可能具有更好的性能:

myArray.findIndex(x => x.hello === 'stevie')

【讨论】:

  • 使用 ES6 的好方法
  • 我很惊讶这些方法都不如我的回答中提到的原型 for 循环那样高效。尽管 findIndex 方法对浏览器的支持有点差,但似乎它会做同样的事情,但最终还是会降低性能?有关基准,请参阅我的答案中的链接。
  • 很高兴知道,如果性能对手头的任务很重要。根据我的经验,它很少是 ymmv。
  • @Uniphonic - 2021 年 findIndex 如果所有浏览器都支持,除了 OperaMini 和 IE - caniuse.com/array-find-index
【解决方案4】:
var idx = myArray.reduce( function( cur, val, index ){

    if( val.hello === "stevie" && cur === -1 ) {
        return index;
    }
    return cur;

}, -1 );

【讨论】:

    【解决方案5】:

    我喜欢 Pablo 的回答,但 Array#indexOf 和 A​​rray#map 并不适用于所有浏览器。如果可用,下划线将使用本机代码,但也有备用代码。此外,它还具有 pluck 方法,可以完全实现 Pablo 的匿名 map 方法的功能。

    var idx = _.chain(myArray).pluck("hello").indexOf("Stevie").value();
    

    【讨论】:

    • Array.prototype.map() 支持 IE9+,您可以为 IE8、7、6 使用 Polyfill:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
    • 你可以使用 polyfill 。 . . 或者你可以只使用 underscore 或 lodash,它们基本上是 polyfill,附加了一大堆其他好东西。下划线有什么反对意见?尺寸?
    • 我真的很喜欢下划线,你的回答也很聪明,但恕我直言,巴勃罗的回答是最干净的。
    • 哇,我从没想过要使用这样的链接。我真的很喜欢它使搜索流畅的方式。
    • chain 在这里是多余的。 _.pluck(myArray, 'hello').indexOf('stevie')
    【解决方案6】:

    或原型:

    Array.prototype.indexOfObject = function arrayObjectIndexOf(property, value) {
        for (var i = 0, len = this.length; i < len; i++) {
            if (this[i][property] === value) return i;
        }
        return -1;
    }
    
    myArr.indexOfObject("name", "stevie");
    

    【讨论】:

    • 很方便!虽然我会选择prototype.indexOfObject 以免干扰现有的Array.indexOf 方法。 Array.prototype.indexOfObject = function(property, value) { for (var i = 0, len = this.length; i &lt; len; i++) { if (this[i][property] === value) return i; } return -1; };
    • 我会将它包装在一个自动执行的闭包中,并预先存储旧的,替换函数的第一行类似于if (typeof property === 'string' || typeof property === 'number' || typeof property === 'boolean') return oldIndexOf(property, value);。这是因为这些是不可变的少数类型。如果需要,我还将提供第三个参数以启用回退到本机方法。
    【解决方案7】:

    我比较了几种方法,得到了解决这个问题的最快方法的结果。这是一个for 循环。它比任何其他方法快 5 倍以上。

    这里是测试页面:https://jsbench.me/9hjewv6a98

    【讨论】:

    • 缺少for-of 循环编号?
    • 可惜人们不向下滚动两个答案。这是唯一好的答案。谢谢。
    【解决方案8】:

    虽然,这里的大多数其他答案都是有效的。有时,最好在您将使用它的地方附近制作一个简短的简单功能。

    // indexOf wrapper for the list of objects
    function indexOfbyKey(obj_list, key, value) {
        for (index in obj_list) {
            if (obj_list[index][key] === value) return index;
        }
        return -1;
    }
    // Find the string in the list (default -1)
    var test1 = indexOfbyKey(object_list, 'name', 'Stevie');
    var test2 = indexOfbyKey(object_list, 'last_name', 'some other name');
    

    这取决于对你来说什么是重要的。它可能会节省代码行并且非常聪明地使用单行,或者将通用解决方案放在涵盖各种边缘情况的地方。但有时最好只是说:“我就是这样做的”,而不是让未来的开发人员进行额外的逆向工程工作。特别是如果您像您的问题一样认为自己是“新手”。

    【讨论】:

      【解决方案9】:

      简介

      myArray.indexOf('stevie','hello')
      

      用例:

        /*****NORMAL****/  
      [2,4,5].indexOf(4) ;//OUTPUT 1
       /****COMPLEX*****/
       [{slm:2},{slm:4},{slm:5}].indexOf(4,'slm');//OUTPUT 1
       //OR
       [{slm:2},{slm:4},{slm:5}].indexOf(4,function(e,i){
         return e.slm;
      });//OUTPUT 1
      /***MORE Complex**/
      [{slm:{salat:2}},{slm:{salat:4}},{slm:{salat:5}}].indexOf(4,function(e,i){
         return e.slm.salat;
      });//OUTPUT 1
      

      API:

          Array.prototype.indexOfOld=Array.prototype.indexOf
      
          Array.prototype.indexOf=function(e,fn){
            if(!fn){return this.indexOfOld(e)}
            else{ 
             if(typeof fn ==='string'){var att=fn;fn=function(e){return e[att];}}
              return this.map(fn).indexOfOld(e);
            }
          };
      

      【讨论】:

        【解决方案10】:

        如果您的对象与您在数组中使用的对象是同一个对象,您应该能够以与字符串相同的方式获取该对象的索引。

        var hello = {
            hello: 'world',
            foo: 'bar'
        };
        var qaz = {
            hello: 'stevie',
            foo: 'baz'
        }
        
        var qazCLONE = { // new object instance and same structure
            hello: 'stevie',
            foo: 'baz'
        }
        
        var myArray = [hello,qaz];
        
        myArray.indexOf(qaz) // should return 1
        myArray.indexOf(qazCLONE) // should return -1
        

        【讨论】:

        • 这是我一直在寻找的答案,因为我不清楚 IndexOf 是否匹配值或什么。现在我知道我可以使用 IndexOf 来查找我的对象,而不必担心是否有其他具有相同属性的对象。
        【解决方案11】:

        我在这里对各种答案进行了一些性能测试,任何人都可以自己运行它们:

        https://jsperf.com/find-index-of-object-in-array-by-contents

        根据我在 Chrome 中的初始测试,以下方法(使用在原型中设置的 for 循环)是最快的:

        Array.prototype.indexOfObject = function (property, value) {
            for (var i = 0, len = this.length; i < len; i++) {
                if (this[i][property] === value) return i;
            }
            return -1;
        }
        
        myArray.indexOfObject("hello", "stevie");
        

        此代码是 Nathan Zaetta 答案的略微修改版本。

        在性能基准测试中,我尝试了目标位于 1000 个对象数组的中间(索引 500)和最末端(索引 999),即使我将目标作为最后一项放入数组(意味着它必须循环遍历数组中的每一项才能找到它)它仍然以最快的速度结束。

        此解决方案还具有重复执行最简洁的优点之一,因为只需要重复最后一行:

        myArray.indexOfObject("hello", "stevie");
        

        【讨论】:

        • 我正要使用我自己的测试的小提琴来发布这个问题的答案,但是感谢您的回答,我不必再这样做了。我只是想确认您的测试 - 我得到了相同的结果,但使用 while 循环而不是 for 循环和 performance.now()。我希望这个答案得到更多的支持,并且我早点看到它,它会为我节省一些时间......
        【解决方案12】:
        array.filter(function(item, indx, arr){ return(item.hello === 'stevie'); })[0];
        

        注意[0]

        Antonio Laguna的答案中使用reduce是正确的。

        为简洁道歉...

        【讨论】:

          【解决方案13】:

          试试这个:

          console.log(Object.keys({foo:"_0_", bar:"_1_"}).indexOf("bar"));
          

          https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/keys

          【讨论】:

            【解决方案14】:

            简单:

            myArray.indexOf(myArray.filter(function(item) {
                return item.hello == "stevie"
            })[0])
            

            【讨论】:

              【解决方案15】:

              基本上可以使用原生方便的函数Array.prototype.findIndex()

              如果数组中的元素满足提供的测试功能,则 findIndex() 方法返回数组中的索引。否则返回 -1。

              请注意,Internet Explorer、Opera 和 Safari 不支持它,但您可以使用下面链接中提供的 Polyfill。

              更多信息:

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

              var hello = {
                hello: 'world',
                foo: 'bar'
              };
              var qaz = {
                hello: 'stevie',
                foo: 'baz'
              }
              
              var myArray = [];
              myArray.push(hello, qaz);
              
              var index = myArray.findIndex(function(element, index, array) {
                if (element.hello === 'stevie') {
                  return true;
                }
              });
              alert('stevie is at index: ' + index);

              【讨论】:

                【解决方案16】:

                如果您只对寻找职位感兴趣,请参阅@Pablo's answer

                pos = myArray.map(function(e) { return e.hello; }).indexOf('stevie');

                但是,如果您期待找到元素(即,如果您正在考虑做这样的事情myArray[pos]),那么有一个更有效的单行 strong> 方法,使用filter

                element = myArray.filter((e) =&gt; e.hello === 'stevie')[0];

                查看性能结果(~ +42% ops/sec): http://jsbench.github.io/#7fa01f89a5dc5cc3bee79abfde80cdb3

                【讨论】:

                  【解决方案17】:

                  请参阅此示例:http://jsfiddle.net/89C54/

                  for (i = 0; i < myArray.length; i++) {
                      if (myArray[i].hello === 'stevie') {
                          alert('position: ' + i);
                          return;
                      }
                  }
                  

                  它从零开始计数。

                  【讨论】:

                    【解决方案18】:

                    我制作了一个通用函数来检查以下代码是否适用于任何对象

                    function indexOfExt(list, item) {
                        var len = list.length;
                    
                        for (var i = 0; i < len; i++) {
                            var keys = Object.keys(list[i]);
                            var flg = true;
                            for (var j = 0; j < keys.length; j++) {
                                var value = list[i][keys[j]];
                                if (item[keys[j]] !== value) {
                                    flg = false;
                                }
                            }
                            if (flg == true) {
                                return i;
                            }
                        }
                        return -1;
                    }
                    
                    var items = [{ "hello": 'world', "foo": 'bar' }];
                    var selectedItem = { "hello": 'world', "foo": 'bar' };
                    alert(items.indexOf(selectedItem));
                    alert(indexOfExt(items, selectedItem));
                    

                    第一个警报将返回 -1(表示未找到匹配项),第二个警报将返回 0(表示找到匹配项)。

                    【讨论】:

                      【解决方案19】:

                      underscore.js library 使用_.findIndex

                      这是示例 _.findIndex([{a:1},{a: 2,c:10},{a: 3}], {a:2,c:10}) //1

                      【讨论】:

                      • 如果建议来自其他库的方法,您应该提及它们的来源。
                      • @Steve Bennett 很好用。图书馆现在在 lodash 中
                      【解决方案20】:

                      使用 ES6 findIndex method,无需 lodash 或任何其他库,您可以编写:

                      function deepIndexOf(arr, obj) {
                        return arr.findIndex(function (cur) {
                          return Object.keys(obj).every(function (key) {
                            return obj[key] === cur[key];
                          });
                        });
                      }
                      

                      这将比较对象的直接属性,但不会递归到属性中。

                      如果您的实现还没有提供findIndex(大多数不提供),您可以添加一个支持此搜索的轻型 polyfill:

                      function deepIndexOf(arr, obj) {
                        function findIndex = Array.prototype.findIndex || function (pred) {
                          for (let i = 0; i < this.length; ++i) {
                            if (pred.call(this, this[i], i)) {
                              return i;
                            }
                          }
                      
                          return -1;
                        }
                      
                        return findIndex.call(arr, function (cur) {
                          return Object.keys(obj).every(function (key) {
                            return obj[key] === cur[key];
                          });
                        });
                      }
                      

                      (来自我对this dupe的回答)

                      【讨论】:

                        【解决方案21】:

                        除了@Monika Garg answer,您还可以使用findIndex()(有一个polyfill 用于不支持的浏览器)。

                        我看到人们对这个答案投了反对票,我希望他们这样做是因为语法错误,因为在我看来,这是最优雅的方式。

                        如果数组中的元素满足提供的测试功能,则 findIndex() 方法返回数组中的索引。否则返回 -1。

                        例如:

                        var hello = {
                          hello: 'world',
                          foo: 'bar'
                        };
                        var qaz = {
                          hello: 'stevie',
                          foo: 'baz'
                        }
                        
                        var myArray = [];
                        myArray.push(hello,qaz);
                        
                        var index = myArray.findIndex(function(element) {
                          return element.hello == 'stevie';
                        });
                        
                        alert(index);

                        【讨论】:

                        【解决方案22】:

                        你可以使用 findIndex() 方法:

                        cosnt myIndex=myArray.findIndex(el=>el.hello==='stevie')
                        

                        如果 myIndex

                        【讨论】:

                        • 这似乎与其他多个回答相同的问题重复
                        【解决方案23】:

                        这是在数组中查找对象索引的方法

                            var myArray = [{  hello: 'world',
                                foo: 'bar'
                            },{
                                hello: 'stevie',
                                foo: 'baz'
                            }];
                        
                        
                        
                            for (i = 0; i < myArray.length; i++) {
                                if (myArray[i].hello === 'stevie') {
                                    alert('position: ' + i);
                                    return;
                                }
                            }
                        

                        【讨论】:

                          【解决方案24】:

                          这无需自定义代码即可工作

                          var arr, a, found;
                          arr = [{x: 1, y: 2}];
                          a = {x: 1, y: 2};
                          found = JSON.stringify(arr).indexOf(JSON.stringify(a)) > - 1;
                          // found === true
                          

                          注意:这并没有给出实际的索引,它只告诉你的对象是否存在于当前数据结构中

                          【讨论】:

                          • 这是无效的,因为它不允许获取任何索引
                          【解决方案25】:

                          你可以简单地使用

                          const someId = 2;
                          const array = [{id:1}, {id:2}, {id:3}];
                          const index = array.reduce((i, item, index) => item.id === someId ? index : i, -1);
                          alert('someId ' + someId + ' is at index ' + index);

                          没有下划线,没有for,只是一个reduce。

                          【讨论】:

                            【解决方案26】:
                            var hello = {hello: "world",  foo: "bar"};
                            var qaz = {hello: "stevie", foo: "baz"};
                            var myArray = [];
                            myArray.push(hello,qaz);
                            
                            function indexOfObject( arr, key, value   ) {
                                var j = -1;
                                var result = arr.some(function(obj, i) { 
                                    j++;
                                    return obj[key] == value;
                                })
                            
                                if (!result) {
                                    return -1;
                                } else {
                                    return j;
                                };
                            }
                            
                            alert(indexOfObject(myArray,"hello","world"));
                            

                            【讨论】:

                            • 使用数组的一些方法。
                            【解决方案27】:

                            此处的大多数答案响应并未解决所有情况。 我发现这个解决方案更好:

                            const isInarray = myArr.filter((obj) => obj.hello === 'stevie' && obj.foo === 'baz').length > 0;
                            if (!isInArray) {
                             ....
                            }
                            

                            【讨论】:

                              【解决方案28】:

                              您可以创建自己的原型来执行此操作:

                              类似:

                              Array.prototype.indexOfObject = function (object) {
                                  for (var i = 0; i < this.length; i++) {
                                      if (JSON.stringify(this[i]) === JSON.stringify(object))
                                          return i;
                                  }
                              }
                              

                              【讨论】:

                              【解决方案29】:

                              我更喜欢使用findIndex() 方法:

                               var index = myArray.findIndex('hello','stevie');
                              

                              index 会给你索引号。

                              【讨论】:

                              • 答案、拼写和代码缩进和:)错了吗?
                              • findIndex 不在任何 javascript 标准实现中。对于这种方法,有一个即将到来的(ecma 6)提案,但它的签名不是那样的。请澄清您的意思(可能是方法的名称),给出 findIndex 方法声明或命名您正在使用的库。
                              猜你喜欢
                              • 2015-12-08
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              • 2012-01-08
                              • 1970-01-01
                              • 2015-04-22
                              相关资源
                              最近更新 更多