169

I've been surfing around a little trying to find an efficient way to do this, but have gotten nowhere. I have an array of objects that looks like this:

array[i].id = some number;
array[i].name = some name;

What I want to do is to find the INDEXES of the objects where id is equal to, for example, one of 0,1,2,3 or 4. I suppose I could just do something like :

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 }
}

While this would work, it looks to be quite expensive and slow (not to mention ugly), especially if array.length could be large. Any ideas on how to spruce this up a bit? I thought of using array.indexOf somehow but I don't see how to force the syntax. This

array.indexOf(this.id === 0);

for example, returns undefined, as it probably should.

kaya3
  • 47,440
  • 4
  • 68
  • 97
Petrov
  • 4,200
  • 6
  • 40
  • 61
  • 1
    If you have a plain old array, all you can do is iterate. That's what arrays are, a bunch of objects ordered by array index. – Dave Newton May 11 '12 at 19:31
  • 2
    Just come across this post today, for all latecomers there is a new array method `Array.prototype.findIndex()` in ECMAScript 2015. The accepted answer was awesome tho. – Conrad Lo Dec 13 '16 at 08:02
  • I'm a fan of ES6 syntax (use polyfills, if support on legacy browsers is needed). ES7+ES8 are going to be future – Fr0zenFyr Feb 22 '19 at 05:36
  • Just FYI, if you want to be able to quickly lookup then you should probably not use arrays, but use dictionaries instead (Id, object) – Worthy7 Feb 11 '21 at 03:07

19 Answers19

429

Maybe you would like to use higher-order functions such as "map". Assuming you want search by 'field' attribute:

var elementPos = array.map(function(x) {return x.id; }).indexOf(idYourAreLookingFor);
var objectFound = array[elementPos];
  • 10
    This answer is great because it actually answers the question by providing the index :) – counterbeing Dec 04 '13 at 16:31
  • That's Ok for one criteria but what if one need to compare more than one criteria? – eKelvin Sep 05 '14 at 09:55
  • 3
    @ZeroAbsolute Your applied function (passed to map) can return a hash string which should provide a unique key for each possible combination given by your criteria. For example: `function hashf(el) { return String(el.id) + "_" + String(el.name); }`. This is just a hint: `elementPos = array.map(hashf(x)).indexOf(hash({id:3, name:'Pablo'}));` Obviously, the hash function I provide is not valid for all cases since `'_'` could form part of your values but it is just a quick example you can figure out different hash methods. – Pablo Francisco Pérez Hidalgo Sep 05 '14 at 10:12
  • 1
    What does this return if it isn't found? I assume -1, just curious. I'll experiment. – Nathan C. Tresch Feb 12 '15 at 21:48
  • 1
    @NathanC.Tresch It returns -1 because that is `indexOf` return value when it can't locate a given value. – Pablo Francisco Pérez Hidalgo Feb 13 '15 at 07:22
  • @PabloFranciscoPérezHidalgo Yeah, I assumed that was it. Thanks for the response and the answer, it works well. – Nathan C. Tresch Feb 13 '15 at 16:32
  • 1
    A quick example to copy-paste for you to play with Pablo's simple solution to this very common problem! `var arrayOfObjects = [ { a: 1, aa: "two"}, // 0 { a: "asdf", aa: 2}, // 1 { a: "cat", aa: "dog"} // 2 ]; var elementPos = arrayOfObjects.map(function(x) {return x.aa; }).indexOf('dog'); var objectFound = arrayOfObjects[elementPos]; console.log(elementPos, objectFound); // 2 { a: 'cat', aa: 'dog' }` – Rick Jul 30 '15 at 00:45
  • 4
    Hi everyone instead of using two methods `map, indexOf` you can use just one called `findIndex`....... Ex: `[{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 Dec 21 '16 at 10:06
  • 1
    Works only if the item appears once. If the item is present more than once, the indexOf method returns the position of just the first occurrence. So it will not provide an array with all of the indices that the item is present – Ioannis K. Moutsatsos Aug 04 '17 at 18:42
  • 1
    for looping over 5 million single object sized items the time difference for checking in a forEach loop is marginal – mjwrazor Aug 25 '17 at 21:14
  • also there is a tiny utility for this called [super-array](https://www.npmjs.com/package/super-array) – patotoma Sep 24 '17 at 17:43
  • This answer is not the best and does not fully answer the question @counterbeing this is definitely not the fastest way. map() is extremely slow with large arrays. consider using new Set() or some() etc. – arled Apr 17 '21 at 18:16
  • 1
    map is slow. A good old for (inverted) loop and break on hit is the way to go. – mak Aug 29 '21 at 17:09
  • var elementPos = array.map((x=>x.id).indexOf(idYourAreLookingFor); var objectFound = array[elementPos]; – Shinoy Babu Sep 26 '21 at 02:24
102

The simplest and easiest way to find element index in array.

ES5 syntax: [{id:1},{id:2},{id:3},{id:4}].findIndex(function(obj){return obj.id == 3})

ES6 syntax: [{id:1},{id:2},{id:3},{id:4}].findIndex(obj => obj.id == 3)

Umair Ahmed
  • 8,337
  • 4
  • 29
  • 37
  • 5
    I believe this is the most elegant solution. For those worried about backwards compatibility you can find the polyfill for `findIndex` at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex – mrogers Jan 11 '17 at 21:50
  • 3
    I get a warning in my ES6 lint tool that the `obj.id == 3` operator used here can cause unexpected type conversion, so use the `obj.id === 3` operator instead, which tests for equal value and type. – thclark Jul 03 '18 at 13:03
  • 5
    This answer is at least 3.5 times faster than the accepted answer above. Using `var elementPos = array.map(function(x) {return x.id; }).indexOf(idYourAreLookingFor);` it took 0.03500000002532033 milliseconds Using `[{id:1},{id:2},{id:3},{id:4}].findIndex(obj => obj.id == 3)` it took 0.00999999747378752 milliseconds. – Ovidio Reyna Jul 19 '19 at 15:45
  • 3
    THIS ANSWER is the most EFFICIENT since it doesn't iterate the whole array. The selected answer will map complete array and then findIndex which is bound to iterate through whole array once – Karun Aug 02 '19 at 11:30
  • 2
    This is the correct way to get **INDEX** `const index = this.pages.findIndex(object => { return object.id === id; }); console.log('index', index);` – Parth Developer Jan 20 '21 at 14:09
26

The new Array method .filter() would work well for this:

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

jQuery can also do this with .grep()

edit: it is worth mentioning that both of these functions just iterate under the hood, there won't be a noticeable performance difference between them and rolling your own filter function, but why re-invent the wheel.

jbabey
  • 45,965
  • 12
  • 71
  • 94
21

If you care about performance, dont go with find or filter or map or any of the above discussed methods

Here is an example demonstrating the fastest method. HERE is the link to the actual test

Setup block

var items = []

for(var i = 0; i < 1000; i++) {
    items.push({id: i + 1})
}

var find = 523

Fastest Method

var index = -1
for(var i = 0; i < items.length; i++) {
    if(items[i].id === find) {
        index = i;
        break;
    }
}

Slower Methods

items.findIndex(item => item.id === find)

SLOWEST method

items.map(item => item.id).indexOf(find);
PirateApp
  • 5,433
  • 4
  • 57
  • 90
10

Since there's no answer using regular array 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) 

console.log(found === two) // true

console.log(arr.indexOf(found)) // 1
enapupe
  • 15,691
  • 3
  • 29
  • 45
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

the result is a look up list for the id. with the given id we get the index of the record.

Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
7

const index = array.findIndex(item => item.id === 'your-id');

This should get you the index of item in array with id === your-id

array = [ {id:1}, {id:2} ];

const index = array.findIndex(item => item.id === 2);

console.log(index);
PulpDood
  • 411
  • 5
  • 9
6
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);
    }
}
Elliot Bonneville
  • 51,872
  • 23
  • 96
  • 123
5

A new way using ES6

let picked_element = array.filter(element => element.id === 0);
Silve2611
  • 2,198
  • 2
  • 34
  • 55
3

Using the ES6 map function:

let idToFind = 3;
let index = someArray.map(obj => obj.id).indexOf(idToFind);
JoeTidee
  • 24,754
  • 25
  • 104
  • 149
3

Sometimes the old ways are the best, as noted by @PirateBay.

With ES 6/7 ".find" is very fast too & stops when it matches (unlike .map or .filter)

items.find(e => e.id === find)?.id
SarahJ
  • 51
  • 1
  • 2
2

Sounds to me like you could create a simple iterator with a callback for testing. Like so:

function findElements(array, predicate)
{
    var matchingIndices = [];

    for(var j = 0; j < array.length; j++)
    {
        if(predicate(array[j]))
           matchingIndices.push(j);
    }

    return matchingIndices;
}

Then you could invoke like so:

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
Tejs
  • 40,736
  • 10
  • 68
  • 86
2

Adapting Tejs's answer for mongoDB and Robomongo I changed

matchingIndices.push(j);

to

matchingIndices.push(NumberInt(j+1));
josliber
  • 43,891
  • 12
  • 98
  • 133
user2584621
  • 2,305
  • 2
  • 15
  • 9
2

To summary all of the great answer above and additional of my answer regarding find all the indexes occurred from some of the comment.

  1. To return the index of the first occurrence.

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. To return the index array of all occurrences, using 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, [])
trungk18
  • 19,744
  • 8
  • 48
  • 83
1

I've created a tiny utility called super-array where you can access items in an array by a unique identifier with O(1) complexity. Example:

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'}
patotoma
  • 1,069
  • 2
  • 11
  • 15
  • You may want to read [How to offer personal open-source libraries?](//meta.stackexchange.com/q/229085) before posting this everywhere. – Martijn Pieters Sep 24 '17 at 18:12
  • @MartijnPieters I've posted it only to a few relevant questions and the project is MIT free so what's the deal? Maybe you could be a bit more tolerating. – patotoma Sep 24 '17 at 18:55
1

One simple method to find index of object in an array based on a specific match.

//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
Khattak01
  • 365
  • 4
  • 10
0

As I can't comment yet, I want to show the solution I used based on the method Umair Ahmed posted, but when you want to search for a key instead of a value:

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

I understand that it doesn't answer the expanded question, but the title doesn't specify what was wanted from each object, so I want to humbly share this to save headaches to others in the future, while I undestart it may not be the fastest solution.

Xander N
  • 3
  • 3
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;
}

will return index 1 (Works only in ES 2016)

eXtreme
  • 244
  • 3
  • 18
0

I like this method because it's easy to compare to any value in the object no matter how deep it's nested.

 while(i<myArray.length && myArray[i].data.value!==value){
  i++; 
}
// i now hows the index value for the match. 
 console.log("Index ->",i );
Daniel Lefebvre
  • 364
  • 4
  • 11