JS use indexOf on an array of objects

116 views Asked by At

I want to use indexOf() on an array of objects. For example:

var arr;
var arr[0] = {a: 1, b: 2};
var arr[1] = {a: 1, b: 3};
var obj = {a: 1, b: 2};

console.log(arr.indexOf(obj));

This will print -1 because arr[0] does not equal obj. How can I make this work (i.e., print 0)?

3

There are 3 answers

0
StackSlave On

I created a similar function which compares almost anything, a while back:

function similar(needle, haystack, exact){
  if(needle === haystack){
    return true;
  }
  if(needle instanceof Date && haystack instanceof Date){
    return needle.getTime() === haystack.getTime();
  }
  if(!needle || !haystack || (typeof needle !== 'object' && typeof haystack !== 'object')){
    return needle === haystack;
  }
  if(needle === null || needle === undefined || haystack === null || haystack === undefined || needle.prototype !== haystack.prototype){
    return false;
  }
  var keys = Object.keys(needle);
  if(exact && keys.length !== Object.keys(haystack).length){
    return false;
  }
  return keys.every(function(k){
    return similar(needle[k], haystack[k]);
  });
}
var obj1 = {a:1, b:[5, 'word'], c:{another:'cool', neat:'not', num:1}, d:'simple string'};
var obj2 = {a:1, b:[5, 'word'], c:{another:'cool', neat:'not', num:1}, d:'simple string'};
console.log(similar(obj1, obj2, true)); // true for exact match
obj2.newProp = 'new value'; // extra haystack prop added
console.log(similar(obj1, obj2, true)); // true for exact - result is false here
console.log(similar(obj1, obj2)); // not exact - obj1 properties and values are in obj2

Of course similar can be made to find the similarIndex of a needle (anything) in an haystack (array of anything), like so:

function similar(needle, haystack, exact){
  if(needle === haystack){
    return true;
  }
  if(needle instanceof Date && haystack instanceof Date){
    return needle.getTime() === haystack.getTime();
  }
  if(!needle || !haystack || (typeof needle !== 'object' && typeof haystack !== 'object')){
    return needle === haystack;
  }
  if(needle === null || needle === undefined || haystack === null || haystack === undefined || needle.prototype !== haystack.prototype){
    return false;
  }
  var keys = Object.keys(needle);
  if(exact && keys.length !== Object.keys(haystack).length){
    return false;
  }
  return keys.every(function(k){
    return similar(needle[k], haystack[k]);
  });
}
function similarIndex(needle, haystack, exact){
  for(var i=0,l=haystack.length; i<l; i++){
    if(similar(needle, haystack[i], exact)){
      return i;
    }
  }
  return -1;
}
var objArray = [{a:1, b:[5, 'wtf'], c:{another:'cool', neat:'not', num:1}, d:'simple string'}, {a:1, b:[5, 'word'], c:{another:'cool', neat:'not', num:1}, d:'simple string'}, {a:1, b:[5, 'word'], c:{another:'cool', neat:'not', num:4}, d:'simple string'}];
var testObj = {a:1, b:[5, 'word'], c:{another:'cool', neat:'not', num:1}, d:'simple string'};
console.log(similarIndex(testObj, objArray, true)); // exact - index is 1 in this case
objArray[1].newProp = 'new value'; // haystack array element 1 gets new property and value
console.log(similarIndex(testObj, objArray, true)); // exact - -1 result here
console.log(similarIndex(testObj, objArray)); // not exact - index 1

0
Jose Nuno On

You would have to compare the properties. Something like this would work:

var arr = [];
arr[0] = {a: 1, b: 2};
arr[1] = {a: 1, b: 3};

console.log(arr.findIndex(o => o.a === 1 && o.b === 2));
//0
console.log(arr.findIndex(o => o.a === 1 && o.b === 3));
//1

0
Steve On

The array.findIndex() function will bring back the index for the first value that the comparing function results are true. I have a function that I use to compare if two objects are equal that can be used in this example.

var obj = {a: 1, b: 2};
var arr = [];
arr[0] = {a: 1, b: 2};
arr[1] = {a: 1, b: 3};

var idx = arr.findIndex(element => areObjsEqual(element,obj));
console.log(`The index is: ${idx}`);

//Function to check if two js objects are equal
function areObjsEqual(a, b) {
    // Create arrays of property names
    var aProps = Object.getOwnPropertyNames(a);
    var bProps = Object.getOwnPropertyNames(b);

    // If number of properties is different,
    // objects are not equivalent
    if (aProps.length != bProps.length) { return false;}
    
    //loop through the object and compare the property values
    for (var i = 0; i < aProps.length; i++) {
        var propName = aProps[i];
        // If values of same property are not equal,
        // objects are not equivalent
        if (a[propName] !== b[propName]) {
            return false;
        }
    }
    // If we made it this far, objects
    // are considered equivalent
    return true;
}