对象数组中的 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 的新手,我不知道是否有简单的方法,或者我是否应该构建自己的函数来做到这一点。
【问题讨论】:
你想合并hello
和qaz
这两个对象吗?
不,我没有。我想要一个数组中的对象列表。
啊好吧!你想知道整个对象在数组中的位置,它有一个定义的属性。
我找到了一个非常简单的函数来解决这个 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 最坏的情况,一旦找到匹配项就会停止迭代。
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 和 Array#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 < 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) => 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可以判断对象数组中的对象有没有在数组中吗