对象数组中的 indexOf 方法?

Posted

技术标签:

【中文标题】对象数组中的 indexOf 方法?【英文标题】:indexOf method in an object array? 【发布时间】: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] (***.com/a/16100446/1937255) ES6 Array.indexOf 比公认的答案更好(如果 ES6 适合您) - 请参阅下面的完整示例 【参考方案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

只是一些注释:

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

例如,

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

【讨论】:

该函数的搜索词比较错误,因为它应该是 searchTerm :) 多次出现 @SteveBennett 这是一个性能优化版本;数组的长度只需确定一次(当初始化 for 循环的变量时)。在您的情况下,每次迭代都会重新检查长度。另请参阅 ***.com/questions/5349425/… 和 ***.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);

【讨论】:

方法看起来很优雅,但是根据MDN没有IE支持? developer.mozilla.org/en/docs/Web/JavaScript/Reference/… 尝试使用 polyfill(答案中的链接)。【参考方案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;
    

【讨论】:

不好的做法,打破封装:developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/… 这也会破坏递归定义的对象。【参考方案29】:

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

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

index 会给你索引号。

【讨论】:

答案、拼写和代码缩进和:)错了吗? findIndex 不在任何 javascript 标准实现中。对于这种方法,有一个即将到来的(ecma 6)提案,但它的签名不是那样的。请澄清您的意思(可能是方法的名称),给出 findIndex 方法声明或命名您正在使用的库。

以上是关于对象数组中的 indexOf 方法?的主要内容,如果未能解决你的问题,请参考以下文章

javascript中的IndexOf方法比遍历数组更有效吗?

js 数组的indexOf可以判断对象数组中的对象有没有在数组中吗

js中判断对象数组中是不是有某个属性值

如何获取数组里对象的某个值

JavaScript——数组的indexOf()方法在IE8中的兼容性问题

数组对象去重