563

I have an array like this:

[{prop1:"abc",prop2:"qwe"},{prop1:"bnmb",prop2:"yutu"},{prop1:"zxvz",prop2:"qwrq"},...]

How can I get the index of the object that matches a condition, without iterating over the entire array?

For instance, given prop2=="yutu", I want to get index 1.

I saw .indexOf() but think it's used for simple arrays like ["a1","a2",...]. I also checked $.grep() but this returns objects, not the index.

1

14 Answers 14

1210

As of 2016, you're supposed to use Array.findIndex (an ES2015/ES6 standard) for this:

a = [
  {prop1:"abc",prop2:"qwe"},
  {prop1:"bnmb",prop2:"yutu"},
  {prop1:"zxvz",prop2:"qwrq"}];
    
index = a.findIndex(x => x.prop2 ==="yutu");

console.log(index);

It's supported in Google Chrome, Firefox and Edge. For Internet Explorer, there's a polyfill on the linked page.

Performance note

Function calls are expensive, therefore with really big arrays a simple loop will perform much better than findIndex:

let test = [];

for (let i = 0; i < 1e6; i++)
    test.push({prop: i});


let search = test.length - 1;
let count = 100;

console.time('findIndex/predefined function');
    let fn = obj => obj.prop === search;

    for (let i = 0; i < count; i++)
        test.findIndex(fn);
console.timeEnd('findIndex/predefined function');


console.time('findIndex/dynamic function');
    for (let i = 0; i < count; i++)
        test.findIndex(obj => obj.prop === search);
console.timeEnd('findIndex/dynamic function');


console.time('loop');
    for (let i = 0; i < count; i++) {
        for (let index = 0; index < test.length; index++) {
            if (test[index].prop === search) {
                break;
            }
        }
    }
console.timeEnd('loop');

As with most optimizations, this should be applied with care and only when actually needed.

Sign up to request clarification or add additional context in comments.

7 Comments

I'm not seeing the need for a temporary array here. Just use the fact the iterator function closes over the context and use a variable. Also, the non-jQuery version doesn't work (suppose it's found at index 0?). Both solutions do more iteration than required, which is less than ideal if the array is large (although the odds of it being so big a human would notice are low, unless lookups are happening a lot).
@ thg435: Still think it's a bit of a Rube Goldberg machine where a simple lever would do the trick. :-) But hey, it works!
Small note; use jQuery.map to avoid plugin conflicts :) As a self-imposed rule I always avoid using $.
I guess other than findIndex() the last snippet which involves map() and filter() is the only chainable solution mentioned under this question.
I like the suggestion to use the polyfill. However the code as written still fails in IE11 even with the polyfill because of the usage of an arrow / lambda function. Re-written as index = a.findIndex(function (x) { return x.prop2 == "yutu" }) fixed the issue so that with the polyfill code, findIndex worked in IE11
|
36

How can I get the index of the object tha match a condition (without iterate along the array)?

You cannot, something has to iterate through the array (at least once).

If the condition changes a lot, then you'll have to loop through and look at the objects therein to see if they match the condition. However, on a system with ES5 features (or if you install a shim), that iteration can be done fairly concisely:

var index;
yourArray.some(function(entry, i) {
    if (entry.prop2 == "yutu") {
        index = i;
        return true;
    }
});

That uses the new(ish) Array#some function, which loops through the entries in the array until the function you give it returns true. The function I've given it saves the index of the matching entry, then returns true to stop the iteration.

Or of course, just use a for loop. Your various iteration options are covered in this other answer.

But if you're always going to be using the same property for this lookup, and if the property values are unique, you can loop just once and create an object to map them:

var prop2map = {};
yourArray.forEach(function(entry) {
    prop2map[entry.prop2] = entry;
});

(Or, again, you could use a for loop or any of your other options.)

Then if you need to find the entry with prop2 = "yutu", you can do this:

var entry = prop2map["yutu"];

I call this "cross-indexing" the array. Naturally, if you remove or add entries (or change their prop2 values), you need to update your mapping object as well.

1 Comment

Thanks for the explanation! The solution with jQuery pointed by thg435 did what I wanted...
29

What TJ Crowder said, everyway will have some kind of hidden iteration, with lodash this becomes:

var index = _.findIndex(array, {prop2: 'yutu'})

1 Comment

while you can just loop through various ways to get the index, find Index is the best solution, even adopted in ES6 into native array methods
20
var CarId = 23;

//x.VehicleId property to match in the object array
var carIndex = CarsList.map(function (x) { return x.VehicleId; }).indexOf(CarId);

And for basic array numbers you can also do this:

var numberList = [100,200,300,400,500];
var index = numberList.indexOf(200); // 1

You will get -1 if it cannot find a value in the array.

Comments

15

Using Array.map() and Array.indexOf(string)

const arr = [{
  prop1: "abc",
  prop2: "qwe"
}, {
  prop1: "bnmb",
  prop2: "yutu"
}, {
  prop1: "zxvz",
  prop2: "qwrq"
}]

const index = arr.map(i => i.prop2).indexOf("yutu");

console.log(index);

Comments

13
var index;
yourArray.some(function (elem, i) {
    return elem.prop2 === 'yutu' ? (index = i, true) : false;
});

Iterate over all elements of array. It returns either the index and true or false if the condition does not match.

Important is the explicit return value of true (or a value which boolean result is true). The single assignment is not sufficient, because of a possible index with 0 (Boolean(0) === false), which would not result an error but disables the break of the iteration.

Edit

An even shorter version of the above:

yourArray.some(function (elem, i) {
    return elem.prop2 === 'yutu' && ~(index = i);
});

10 Comments

What does ~ character do in your second snippet?
@serkan, it is a bitwise NOT | operator, it is a short version of getting from an index (with -1) a truthy/falsy result, if an index exists.
thanks Nina, Without the ~ character, code works as it is, is not it?
@serkan, your question is not clear, but without ~ it does not work like that.
oh, !!(index = 0) and !!~(index = 0) difference indeed. Thanks!
|
5

I have seen many solutions in the above.

Here I am using map function to find the index of the search text in an array object.

I am going to explain my answer with using students data.

  • step 1: create array object for the students(optional you can create your own array object).
    var students = [{name:"Rambabu",htno:"1245"},{name:"Divya",htno:"1246"},{name:"poojitha",htno:"1247"},{name:"magitha",htno:"1248"}];

  • step 2: Create variable to search text
    var studentNameToSearch = "Divya";

  • step 3: Create variable to store matched index(here we use map function to iterate).
    var matchedIndex = students.map(function (obj) { return obj.name; }).indexOf(studentNameToSearch);

var students = [{name:"Rambabu",htno:"1245"},{name:"Divya",htno:"1246"},{name:"poojitha",htno:"1247"},{name:"magitha",htno:"1248"}];

var studentNameToSearch = "Divya";

var matchedIndex = students.map(function (obj) { return obj.name; }).indexOf(studentNameToSearch);

console.log(matchedIndex);

alert("Your search name index in array is:"+matchedIndex)

Comments

3

You can use the Array.prototype.some() in the following way (as mentioned in the other answers):

https://jsfiddle.net/h1d69exj/2/

function findIndexInData(data, property, value) {
    var result = -1;
    data.some(function (item, i) {
        if (item[property] === value) {
            result = i;
            return true;
        }
    });
    return result;
}
var data = [{prop1:"abc",prop2:"qwe"},{prop1:"bnmb",prop2:"yutu"},{prop1:"zxvz",prop2:"qwrq"}]



alert(findIndexInData(data, 'prop2', "yutu")); // shows index of 1

Comments

3
function findIndexByKeyValue(_array, key, value) {
    for (var i = 0; i < _array.length; i++) { 
        if (_array[i][key] == value) {
            return i;
        }
    }
    return -1;
}
var a = [
    {prop1:"abc",prop2:"qwe"},
    {prop1:"bnmb",prop2:"yutu"},
    {prop1:"zxvz",prop2:"qwrq"}];
var index = findIndexByKeyValue(a, 'prop2', 'yutu');
console.log(index);

Comments

2

Another easy way is :

 function getIndex(items) {
        for (const [index, item] of items.entries()) {
            if (item.prop2 === 'yutu') {
                return index;
            }
        }
    }

const myIndex = getIndex(myArray);

1 Comment

sometimes you may want to just use double equal "=="
1

Georg have already mentioned ES6 have Array.findIndex for this. And some other answers are workaround for ES5 using Array.some method.

One more elegant approach can be

var index;
for(index = yourArray.length; index-- > 0 && yourArray[index].prop2 !== "yutu";);

At the same time I will like to emphasize, Array.some may be implemented with binary or other efficient searching technique. So, it might perform better over for loop in some browser.

Comments

0

Why do you not want to iterate exactly ? The new Array.prototype.forEach are great for this purpose!

You can use a Binary Search Tree to find via a single method call if you want. This is a neat implementation of BTree and Red black Search tree in JS - https://github.com/vadimg/js_bintrees - but I'm not sure whether you can find the index at the same time.

Comments

0

One step using Array.reduce() - no jQuery

var items = [{id: 331}, {id: 220}, {id: 872}];

var searchIndexForId = 220;
var index = items.reduce(function(searchIndex, item, index){
  if(item.id === searchIndexForId) { 
    console.log('found!');
    searchIndex = index;
  }
  return searchIndex;
}, null);

will return null if index was not found.

Comments

0
var list =  [
                {prop1:"abc",prop2:"qwe"},
                {prop1:"bnmb",prop2:"yutu"},
                {prop1:"zxvz",prop2:"qwrq"}
            ];

var findProp = p => {
    var index = -1;
    $.each(list, (i, o) => {
        if(o.prop2 == p) {
            index = i;
            return false; // break
        }
    });
    return index; // -1 == not found, else == index
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.