1

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();
poolts
  • 23
  • 6
  • You're right it has something to do with object equality because `[] == []` is `false`. – ibrahim mahrir Feb 20 '17 at 21:45
  • I had an answer for this question, in this case could be util comparing arrays as string, https://jsfiddle.net/dbpLenwu/ – Luis González Feb 20 '17 at 21:55
  • @trincot I don't believe this is a duplicate question as I was looking for the best way to find the index of the array and also wanted some background information on why indexOf didn't work (which wasn't the main discussion point). Many thanks. – poolts Feb 20 '17 at 21:56
  • see my jsfiddle above maybe could be useful in your case @poolts – Luis González Feb 20 '17 at 21:58
  • It is a duplicate, because in order to find where an array occurrence is, you need to *compare* it. – trincot Feb 20 '17 at 21:58
  • 1
    @trincot Still think it's more associated than duplicated, but close it if you still think otherwise. – poolts Feb 20 '17 at 22:04
  • If you understand that `indexOf` cannot find your array, because it is not in the searched array, you'll see you need to use the techniques discussed in the referenced question. Note that the array you search with is *different*, even though it happens to contain the same primitive values as *another* array -- they are still different arrays. So `indexOf` is of no use. – trincot Feb 20 '17 at 22:18
  • One little trick is convert array to a JSON string and compare them as strings... this will have a performance impact, but if you dont use it too often it works – Diego N. Apr 02 '17 at 09:43

1 Answers1

1

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.

Community
  • 1
  • 1
Pointy
  • 405,095
  • 59
  • 585
  • 614