在对象数组中,查找属性与搜索匹配的对象的索引的最快方法
Posted
技术标签:
【中文标题】在对象数组中,查找属性与搜索匹配的对象的索引的最快方法【英文标题】:In an array of objects, fastest way to find the index of an object whose attributes match a search 【发布时间】:2012-05-20 09:53:06 【问题描述】:我一直在四处寻找一种有效的方法来做到这一点,但一无所获。我有一个看起来像这样的对象数组:
array[i].id = some number;
array[i].name = some name;
我想要做的是找到 id 等于的对象的索引,例如,0、1、2、3 或 4 之一。 我想我可以这样做:
var indexes = [];
for(i=0; i<array.length; i++)
(array[i].id === 0) ? indexes[0] = i
(array[i].id === 1) ? indexes[1] = i
(array[i].id === 2) ? indexes[2] = i
(array[i].id === 3) ? indexes[3] = i
(array[i].id === 4) ? indexes[4] = i
虽然这可行,但它看起来非常昂贵且缓慢(更不用说丑陋了),尤其是在 array.length 可能很大的情况下。关于如何稍微修饰一下的任何想法?我想以某种方式使用 array.indexOf ,但我不知道如何强制使用语法。这个
array.indexOf(this.id === 0);
例如,返回 undefined,它可能应该返回。
【问题讨论】:
如果你有一个普通的旧数组,你所能做的就是迭代。这就是数组,一堆按数组索引排序的对象。 今天刚看到这篇文章,对于所有后来者来说,ECMAScript 2015 中有一个新的数组方法Array.prototype.findIndex()
。接受的答案太棒了。
我是 ES6 语法的粉丝(如果需要对旧版浏览器的支持,请使用 polyfills)。 ES7+ES8 将是未来
仅供参考,如果您希望能够快速查找,那么您可能不应该使用数组,而是使用字典(Id,object)
【参考方案1】:
也许您想使用“地图”等高阶函数。 假设您想按“字段”属性搜索:
var elementPos = array.map(function(x) return x.id; ).indexOf(idYourAreLookingFor);
var objectFound = array[elementPos];
【讨论】:
这个答案很棒,因为它实际上通过提供索引来回答问题:) @ZeroAbsolute 您应用的函数(传递给 map)可以返回一个哈希字符串,该字符串应该为您的标准给出的每个可能的组合提供一个唯一键。例如:function hashf(el) return String(el.id) + "_" + String(el.name);
。这只是一个提示:elementPos = array.map(hashf(x)).indexOf(hash(id:3, name:'Pablo'));
显然,我提供的哈希函数并非对所有情况都有效,因为 '_'
可能构成您的值的一部分,但这只是一个快速示例,您可以找出不同的哈希方法。
如果没有找到会返回什么?我假设-1,只是好奇。我会做实验。
@NathanC.Tresch 它返回-1,因为这是indexOf
在找不到给定值时的返回值。
大家好,不要使用两种方法map, indexOf
,您可以只使用一种称为findIndex
.......例如:[id:1,id:2,id:3,id:4].findIndex(function(obj)return obj.id == 3) OR [id:1,id:2,id:3,id:4].findIndex(obj => obj.id == 3)
【参考方案2】:
在数组中查找元素索引的最简单和最简单的方法。
ES5 语法: [id:1,id:2,id:3,id:4].findIndex(function(obj)return obj.id == 3)
ES6 语法: [id:1,id:2,id:3,id:4].findIndex(obj => obj.id == 3)
【讨论】:
我相信这是最优雅的解决方案。对于那些担心向后兼容性的人,您可以在 developer.mozilla.org/en-US/docs/Web/javascript/Reference/… 找到findIndex
的 polyfill
我在我的 ES6 lint 工具中收到警告,这里使用的 obj.id == 3
运算符可能会导致意外的类型转换,因此请改用 obj.id === 3
运算符,它会测试相等的值和类型。跨度>
这个答案至少比上面接受的答案快 3.5 倍。使用 var elementPos = array.map(function(x) return x.id; ).indexOf(idYourAreLookingFor);
花费了 0.03500000002532033 毫秒使用 [id:1,id:2,id:3,id:4].findIndex(obj => obj.id == 3)
花费了 0.00999999747378752 毫秒。
这个答案是最有效的,因为它不会迭代整个数组。选择的答案将映射完整的数组,然后 findIndex 将遍历整个数组一次
这是获取INDEX的正确方法const index = this.pages.findIndex(object => return object.id === id; ); console.log('index', index);
【参考方案3】:
新的数组方法.filter() 可以很好地解决这个问题:
var filteredArray = array.filter(function (element)
return element.id === 0;
);
jQuery 也可以通过 .grep() 来做到这一点
编辑:值得一提的是,这两个函数都只是在底层迭代,它们与滚动您自己的过滤器函数之间不会有明显的性能差异,但为什么要重新发明***。
【讨论】:
+1,我总是忘记对象上的内置函数。 这不会返回索引。 这并不能回答这个具体问题,但对我有很大帮助!谢谢! 这不会返回索引。【参考方案4】:如果您关心性能,请不要使用 find 或 filter 或 map 或上述任何方法
这是一个演示最快方法的示例。 HERE是实际测试的链接
设置块
var items = []
for(var i = 0; i < 1000; i++)
items.push(id: i + 1)
var find = 523
最快的方法
var index = -1
for(var i = 0; i < items.length; i++)
if(items[i].id === find)
index = i;
break;
较慢的方法
items.findIndex(item => item.id === find)
最慢的方法
items.map(item => item.id).indexOf(find);
【讨论】:
感谢您提供此比较!超级有趣的是性能有多少变化——包括哪种方法更快取决于运行它们的浏览器/JavaScript引擎。 我认为这应该被标记为答案。这显示了最快的方式和较慢的方式。 在您的基准测试中,块 2(使用 findIndex)实际上对我来说更快(在 Microsoft Edge Chromium 83.0.474.0 上) Block 2 现在在 chrome 上也更快了 我已经扩展了基准jsben.ch/19PxA,这第四块是 Chrome 中最快的。 -> items.map(function(x) return x.id; ).indexOf(find);【参考方案5】:array.forEach(function (elem, i) // iterate over all elements of array
indexes[elem.id] = i; // take the found id as index for the
); // indexes array and assign i
结果是 id 的查找列表。使用给定的 id 我们得到记录的索引。
【讨论】:
【参考方案6】:由于使用常规数组find
没有答案:
var one = id: 1, name: 'one';
var two = id: 2, name:'two'
var arr = [one, two]
var found = arr.find((a) => a.id === 2)
found === two // true
arr.indexOf(found) // 1
【讨论】:
【参考方案7】:var indices = [];
var IDs = [0, 1, 2, 3, 4];
for(var i = 0, len = array.length; i < len; i++)
for(var j = 0; j < IDs.length; j++)
if(array[i].id == ID) indices.push(i);
【讨论】:
【参考方案8】:const index = array.findIndex(item => item.id === 'your-id');
这应该会为您提供 id === your-id 的数组中项目的索引
array = [ id:1, id:2 ];
const index = array.findIndex(item => item.id === 2);
console.log(index);
【讨论】:
【参考方案9】:一种使用 ES6 的新方式
let picked_element = array.filter(element => element.id === 0);
【讨论】:
【参考方案10】:使用 ES6 map
函数:
let idToFind = 3;
let index = someArray.map(obj => obj.id).indexOf(idToFind);
【讨论】:
【参考方案11】:在我看来,您可以创建一个带有回调的简单迭代器进行测试。像这样:
function findElements(array, predicate)
var matchingIndices = [];
for(var j = 0; j < array.length; j++)
if(predicate(array[j]))
matchingIndices.push(j);
return matchingIndices;
然后你可以像这样调用:
var someArray = [
id: 1, text: "Hello" ,
id: 2, text: "World" ,
id: 3, text: "Sup" ,
id: 4, text: "Dawg"
];
var matchingIndices = findElements(someArray, function(item)
return item.id % 2 == 0;
);
// Should have an array of [1, 3] as the indexes that matched
【讨论】:
【参考方案12】:改编 Tejs 对 mongoDB 和 Robomongo 的回答我改变了
matchingIndices.push(j);
到
matchingIndices.push(NumberInt(j+1));
【讨论】:
【参考方案13】:总结以上所有出色的答案以及我关于从某些评论中找到所有索引的答案。
-
返回第一次出现的索引。
const array = [ id: 1 , id: 2 , id: 3 , id: 4 , id: 2 ];
const idYourAreLookingFor = 2;
//ES5
//Output: 1
array.map(function (x) return x.id; ).indexOf(idYourAreLookingFor);
//ES6
//Output: 1
array.findIndex(obj => obj.id === idYourAreLookingFor);
-
使用reduce返回所有出现的索引数组。
const array = [ id: 1 , id: 2 , id: 3 , id: 4 , id: 2 ]
const idYourAreLookingFor = 2;
//ES5
//Output: [1, 4]
array.reduce(function (acc, obj, i)
if (obj.id === idYourAreLookingFor)
acc.push(i);
return acc;
, []);
//ES6
//Output: [1, 4]
array.reduce((acc, obj, i) => (obj.id === idYourAreLookingFor) ? acc.concat(i) : acc, [])
【讨论】:
【参考方案14】:我创建了一个名为super-array 的小型实用程序,您可以在其中通过具有 O(1) 复杂度的唯一标识符访问数组中的项目。示例:
const SuperArray = require('super-array');
const myArray = new SuperArray([
id: 'ab1', name: 'John',
id: 'ab2', name: 'Peter',
]);
console.log(myArray.get('ab1')); // id: 'ab1', name: 'John'
console.log(myArray.get('ab2')); // id: 'ab2', name: 'Peter'
【讨论】:
在到处张贴之前,您可能需要阅读How to offer personal open-source libraries?。 @MartijnPieters 我只在几个相关问题上发布了它,而且该项目是免费的 MIT,所以有什么关系?也许你可以宽容一点。【参考方案15】:正如@PirateBay 所指出的,有时旧方法是最好的。
在 ES 6/7 中,“.find”也非常快,并且在匹配时停止(与 .map 或 .filter 不同)
items.find(e => e.id === find)?.id
【讨论】:
【参考方案16】:由于我还不能发表评论,我想根据 Umair Ahmed 发布的方法展示我使用的解决方案,但是当您想要搜索键而不是值时:
["a":true, "f":true, "g":false]
.findIndex(function(element)return Object.keys(element)[0] == "g");
我知道它没有回答扩展的问题,但标题没有说明每个对象想要什么,所以我想谦虚地分享这个以在将来让其他人头疼,同时我可能会取消它不是最快的解决方案。
【讨论】:
【参考方案17】:var test = [
id:1, test: 1,
id:2, test: 2,
id:2, test: 2
];
var result = test.findIndex(findIndex, '2');
console.log(result);
function findIndex(object)
return object.id == this;
将返回索引 1(仅适用于 ES 2016)
【讨论】:
【参考方案18】:我喜欢这种方法,因为它很容易与对象中的任何值进行比较,无论它嵌套多深。
while(i<myArray.length && myArray[i].data.value!==value)
i++;
// i now hows the index value for the match.
console.log("Index ->",i );
【讨论】:
【参考方案19】:一种基于特定匹配在数组中查找对象索引的简单方法。
//list of bookings
const bookings = [
status: "accepted", _id: "6055cadd062eb5153c089121", title: "This is test title", user: "id", team: "id" ,
status: "pending", _id: "6055cb33062eb5153c089122", title: "title1", description: "test description", user: "id", team: "id" ,
status: "accepted", _id: "6055cb3d062eb5153c089123", title: "title2", description: "test description", user: "id", team: "id"
]
//return index of the element if find else return -1
const findIndex = (booking) => bookings.findIndex((b, index) =>
if (b._id === booking._id) return true
)
//test 1
let booking = status: "pending", _id: "6055cb33062eb5153c089122", title: "title2", description: "test description", user: "id", team: "id"
console.log("index >>> ", findIndex(booking))
//output : 1
//test 2
booking = status: "rejected", _id: "6055cb33062eb5153c089198", title: "title3", description: "test description", user: "id", team: "id"
console.log("index >>> ", findIndex(booking))
//output : -1
//test 3
const id = '6055cb3d062eb5153c089123'
console.log("index >>> ", findIndex( _id: id ))
//output : 2
find-searchElementInArrayObObjects
【讨论】:
以上是关于在对象数组中,查找属性与搜索匹配的对象的索引的最快方法的主要内容,如果未能解决你的问题,请参考以下文章
Powershell 问题 - 寻找最快的方法来遍历 500k 个对象以在另一个 500k 对象数组中寻找匹配项