在对象数组中,查找属性与搜索匹配的对象索引的最快方法


135

我一直在网上冲浪,试图找到一种有效的方法来做到这一点,但是却一无所获。我有一个看起来像这样的对象数组:

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);

例如,可能会返回未定义。提前致谢!


1
如果您有一个普通的旧数组,那么您可以做的就是迭代。那就是数组,按数组索引排序的一堆对象。
戴夫·牛顿

2
今天就来看看这篇博文,对于所有后来者Array.prototype.findIndex(),ECMAScript 2015中都有一个新的数组方法。公认的答案非常好。
康拉德·卢

我是ES6语法的忠实拥护者(如果需要旧版浏览器的支持,请使用polyfills)。ES7 + ES8将成为未来
Fr0zenFyr

Answers:


391

也许您想使用诸如“ map”之类的高阶函数。假设您要按“字段”属性进行搜索:

var elementPos = array.map(function(x) {return x.id; }).indexOf(idYourAreLookingFor);
var objectFound = array[elementPos];

9
这个答案是伟大的,因为它实际上通过提供索引:)回答了这个问题
counterbeing

3
@ZeroAbsolute您的应用函数(传递给地图)可以返回哈希字符串,该字符串应为您的条件给出的每种可能的组合提供唯一的键。例如:function hashf(el) { return String(el.id) + "_" + String(el.name); }。这只是一个提示:elementPos = array.map(hashf(x)).indexOf(hash({id:3, name:'Pablo'}));显然,我提供的哈希函数并非对所有情况'_'都有效,因为它可能构成值的一部分,但这只是一个简单的示例,您可以找出不同的哈希方法。
Pablo FranciscoPérezHidalgo 2014年

1
如果找不到,这将返回什么?我假设-1,只是好奇。我会做实验。
内森·T·雷施

1
@ NathanC.Tresch它返回-1,因为这是indexOf当它找不到给定值时的返回值。
Pablo FranciscoPérezHidalgo,2015年

2
大家好,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)
Umair Ahmed

64

在数组中查找元素索引的最简单方法。

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)


4
我相信这是最优雅的解决方案。对于那些担心向后兼容性的人,您可以findIndexdeveloper.mozilla.org/en-US/docs/Web/JavaScript/Reference/…中
polyfill

2
我在ES6皮棉工具中收到一条警告,表示obj.id == 3此处使用的obj.id === 3运算符可能会导致意外的类型转换,因此请改用运算符,该运算符将测试相等的值和类型。
thclark

1
该答案至少比上面接受的答案快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毫秒。
奥维迪奥·雷纳

1
此答复是最有效的,因为它不会迭代整个数组。所选择的答案将映射整个阵列,然后其通过整个阵列结合到迭代一次findIndex
卡伦

26

新的Array方法.filter()可以很好地解决此问题:

var filteredArray = array.filter(function (element) { 
    return element.id === 0;
});

jQuery也可以使用.grep()

编辑:值得一提的是,这两个函数只是在后台进行迭代,它们与滚动自己的过滤器函数之间不会有明显的性能差异,但是为什么要重新发明轮子呢?


+1,我总是忘了在对象上建立这样的内置函数。
Tejs 2012年

59
这不会返回索引。
亚当·格兰特

这不能回答这个特定问题,但是对我有很大帮助!谢谢!
rochasdv

这不会返回索引。
丰富

10

如果您关心性能,请不要使用查找过滤映射或上面讨论的任何方法

这是演示最快方法的示例。这里是实际测试的链接

设置块

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);

2
感谢您提供此比较!超级有趣的是,性能有多少变化-包括哪种方法运行速度更快,这取决于用来运行它们的浏览器/ JavaScript引擎。
伊恩·柯林斯

1
我认为这应该被标记为答案。这显示了最快的方法和较慢的方法。
止痛药

在您的基准测试中,第2块(使用findIndex)实际上对我来说更快(在Microsoft Edge Chromium 83.0.474.0上)
rezadru

2座比以往更快的镀铬以及
科迪mikol

8
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

3

使用ES6的新方法

let picked_element = array.filter(element => element.id === 0);

picked_element在这种情况下是一个数组...
异端猴子

3

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);


2

在我看来,您可以创建一个带有回调的简单迭代器进行测试。像这样:

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

2

改变Tejs对mongoDB和Robomongo的回答,我改变了

matchingIndices.push(j);

matchingIndices.push(NumberInt(j+1));

2

使用ES6 map功能:

let idToFind = 3;
let index = someArray.map(obj => obj.id).indexOf(idToFind);

2

总结以上所有出色的答案,以及我的其他答案,有关找到所有索引均来自某些评论。

  1. 返回第一次出现的索引。

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);

  1. 要返回所有出现的索引数组,请使用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, [])


0

由于我现在还不能发表评论,所以我想显示我根据Umair Ahmed发布的方法使用的解决方案,但是当您要搜索键而不是值时:

[{"a":true}, {"f":true}, {"g":false}]
.findIndex(function(element){return Object.keys(element)[0] == "g"});

我知道它不能回答扩展的问题,但是标题没有指定每个对象想要的内容,因此我想谦虚地分享这些内容,以免将来给其他人带来麻烦,尽管我取消启动它可能不是最快的解决方案。


0

我创建了一个名为超级数组的微型实用程序,您可以通过具有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'}

您可能需要阅读如何提供个人开源库?在将其发布到任何地方之前。
马丁·彼得斯

@MartijnPieters我只将其发布到几个相关的问题上,该项目是MIT的免费项目,所以有什么用?也许您会更宽容一些。
patotoma

0
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中有效)


0

我喜欢这种方法,因为无论嵌套的深度如何,都可以轻松地将其与对象中的任何值进行比较。

 while(i<myArray.length && myArray[i].data.value!==value){
  i++; 
}
// i now hows the index value for the match. 
 console.log("Index ->",i );
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.