poolts
poolts

Reputation: 23

Using indexOf to get index of array in a collection of arrays (Javascript)

What's the best way to find the index of an array in a collection of arrays? Why doesn't indexOf() return the correct index? I'm guessing it's something to do with object equality?

I've seen other solutions loop through the collection and return the index reached when the equality check is met, but I'm still curious as to why indexOf() doesn't do the same thing. Additionally I can't use ES6's find / findIndex due to IE 11 support (as always). I've included my test code below. Many thanks.

var numbers = [ [1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12] ];

function getIndex (numbersToTest) {
  return numbers.indexOf(numbersToTest);
};

function test() {
  console.log( getIndex( [1, 2, 3, 4, 5, 6] ) ); // Except 0
  console.log( getIndex( [7, 8, 9, 10, 11, 12] ) ); // Expect 1
  console.log( getIndex( [2, 1, 3, 4, 5, 6] ) ); // Expect -1 (not in same order)
}

test();

Upvotes: 1

Views: 749

Answers (1)

Pointy
Pointy

Reputation: 413737

Object references (including array references) are compared as reference values; one object reference is equal to another only if both references are to the exact same object. Comparison is not performed based on the content of the arrays, in your case. Even though those arrays you pass in have the same values, they're distinct arrays, and so are not equal to any of the arrays in the original list.

Instead, you need to use something like Array#find (to find the entry) or Array#findIndex (to find the entry's index), passing in a callback that compares the array in numbers with numbersToTest to see if they're equivalent arrays. This question's answers talk about various ways to efficiently compare arrays for equivalence.

For example:

var numbers = [ [1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12] ];

function getIndex (numbersToTest) {
  return numbers.findIndex(function(entry) {
    // Simple comparison that works for an array of numbers
    return entry.length === numbersToTest.length && entry.every(function(number, index) {
      return numbersToTest[index] === number;
    });
  });
};

function test() {
  console.log( getIndex( [1, 2, 3, 4, 5, 6] ) ); // Expect 0
  console.log( getIndex( [7, 8, 9, 10, 11, 12] ) ); // Expect 1
  console.log( getIndex( [2, 1, 3, 4, 5, 6] ) ); // Expect -1 (not in same order)
}

test();

Note that both Array#find and Array#findIndex are newish (ES2015, aka "ES6"), but can be polyfilled for older JavaScript engines.

Upvotes: 1

Related Questions