对象数组中的indexOf方法?

Ant*_*una 471 javascript

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

想象一下这种情况:

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

var myArray = [];
myArray.push(hello,qaz);
Run Code Online (Sandbox Code Playgroud)

现在我想拥有属性indexOf的对象,在这个例子中,它将是.hello'stevie'1

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

Pab*_*lgo 967

我想你可以使用map函数在一行中解决它:

pos = myArray.map(function(e) { return e.hello; }).indexOf('stevie');
Run Code Online (Sandbox Code Playgroud)

  • 老实说,这应该是公认的答案.现在大多数浏览器都支持`Array.prototype.map()` (56认同)
  • 嗯...是不是值得注意Array.prototype.map()创建一个包含映射项的全新数组?那么,如果你有一个包含1000个元素的数组,你先创建了另一个*数组,其中包含1000个元素,然后搜索它?我认为这个方法的性能与简单的for循环相比是值得的.特别是当您在资源有限的移动平台上运行时. (46认同)
  • IE8不支持它,但如果这不是问题,这是最好的解决方案. (9认同)
  • @Doug虽然你对性能的观点确实是正确的,但是对于一个几乎按照定义IO /网络绑定的应用程序而言,他们正确的想法会用一行代码替换七行代码,直到他们描述瓶颈为止? (5认同)
  • 快速版本: `pos = myArray.map((e) => e.hello).indexOf('stevie');` (2认同)
  • 从技术上讲,缩小的js文件也是一行; D (2认同)

Joe*_*Joe 345

除IE之外的所有浏览器都支持Array.prototype.findIndex(非边缘).但是提供的polyfill很不错.

var indexOfStevie = myArray.findIndex(i => i.hello === "stevie");
Run Code Online (Sandbox Code Playgroud)

有地图的解决方案没问题.但是你每次搜索都在迭代整个数组.这只是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;
    }
}
Run Code Online (Sandbox Code Playgroud)

或作为一种功能:

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
Run Code Online (Sandbox Code Playgroud)

只是一些说明:

  1. 不要在数组中使用for ... in循环
  2. 一旦找到"针",一定要突破循环或退出功能
  3. 小心对象平等

例如,

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

  • 不是很重要,但为什么不只是`var i = 0; 我<myArray.length` ... (4认同)
  • @SteveBennett它是一个性能优化版本; 数组的长度只需确定一次(当初始化for循环的变量时).在您的情况下,每次迭代都会检查长度.另见http://stackoverflow.com/questions/5349425/whats-the-fastest-way-to-loop-through-an-array-in-javascript和http://stackoverflow.com/questions/8452317/do- loops-check-the-array-length-every-when-comparison-i-against-array-length然而,如果性能不高prio则无关紧要. (3认同)

Ste*_*ett 115

在ES2015中,这非常简单:

myArray.map(x => x.hello).indexOf('stevie')
Run Code Online (Sandbox Code Playgroud)

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

myArray.findIndex(x => x.hello === 'stevie')
Run Code Online (Sandbox Code Playgroud)

  • 使用 ES6 的好方法 (2认同)

Esa*_*ija 24

var idx = myArray.reduce( function( cur, val, index ){

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

}, -1 );
Run Code Online (Sandbox Code Playgroud)


tan*_*ols 17

我喜欢Pablo的答案,但是Array#indexOf和Array #map不适用于所有浏览器.如果可用,Underscore将使用本机代码,但也会有后备.此外,它还具有完全符合Pablo匿名地图方法的方法.

var idx = _.chain(myArray).pluck("hello").indexOf("Stevie").value();
Run Code Online (Sandbox Code Playgroud)


Nat*_*tta 14

或原型:

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");
Run Code Online (Sandbox Code Playgroud)

  • 很方便!虽然我会选择prototype.indexOfObject,以免干扰exisitng Array.indexOf方法.`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; };` (9认同)

Abd*_*UMI 8

简要

myArray.indexOf('stevie','hello')
Run Code Online (Sandbox Code Playgroud)

用例 :

  /*****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
Run Code Online (Sandbox Code Playgroud)

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);
      }
    };
Run Code Online (Sandbox Code Playgroud)


小智 8

您可以使用findIndex()方法:

cosnt myIndex=myArray.findIndex(el=>el.hello==='stevie')
Run Code Online (Sandbox Code Playgroud)

如果 myIndex < 0 则表示不存在


小智 7

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

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
Run Code Online (Sandbox Code Playgroud)


Uni*_*nic 6

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

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");
Run Code Online (Sandbox Code Playgroud)

这段代码是Nathan Zaetta答案的略微修改版本.

在性能基准测试中,我尝试了目标位于1000个对象数组的中间(索引500)和最终(索引999),即使我将目标放在数组中的最后一项(意思是它必须循环遍历数组中的每一个项目才能找到它仍然最快.

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

myArray.indexOfObject("hello", "stevie");
Run Code Online (Sandbox Code Playgroud)

  • 我正要通过我自己的测试使用小提琴来发布这个问题的答案,但多亏了你的回答,我不再需要了。我只是想确认您的测试 - 我得到了相同的结果,但使用了 `while` 循环而不是 `for` 循环和 `performance.now()`。我希望这个答案得到更多的支持并且我更早看到它,它会为我节省一些时间...... (2认同)

Evg*_*mov 5

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

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


Spi*_*ail 5

虽然,这里的大多数其他答案都是有效的。有时,最好只是在使用位置附近做一个简短的简单函数。

// 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');
Run Code Online (Sandbox Code Playgroud)

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