Comparing Arrays of Objects in JavaScript
Asked Answered
B

19

116

I want to compare 2 arrays of objects in JavaScript code. The objects have 8 total properties, but each object will not have a value for each, and the arrays are never going to be any larger than 8 items each, so maybe the brute force method of traversing each and then looking at the values of the 8 properties is the easiest way to do what I want to do, but before implementing, I wanted to see if anyone had a more elegant solution. Any thoughts?

Bandicoot answered 25/8, 2008 at 22:15 Comment(0)
A
71

EDIT: You cannot overload operators in current, common browser-based implementations of JavaScript interpreters.

To answer the original question, one way you could do this, and mind you, this is a bit of a hack, simply serialize the two arrays to JSON and then compare the two JSON strings. That would simply tell you if the arrays are different, obviously you could do this to each of the objects within the arrays as well to see which ones were different.

Another option is to use a library which has some nice facilities for comparing objects - I use and recommend MochiKit.


EDIT: The answer kamens gave deserves consideration as well, since a single function to compare two given objects would be much smaller than any library to do what I suggest (although my suggestion would certainly work well enough).

Here is a naïve implemenation that may do just enough for you - be aware that there are potential problems with this implementation:

function objectsAreSame(x, y) {
   var objectsAreSame = true;
   for(var propertyName in x) {
      if(x[propertyName] !== y[propertyName]) {
         objectsAreSame = false;
         break;
      }
   }
   return objectsAreSame;
}

The assumption is that both objects have the same exact list of properties.

Oh, and it is probably obvious that, for better or worse, I belong to the only-one-return-point camp. :)

Alicealicea answered 26/8, 2008 at 1:39 Comment(4)
Just to point out the limitation: This looks like it will fail when comparing objects that contain objects. (And as you mention, it will fail when the two objects do not have “the same exact list of properties,” as y is allowed to be a super-set of x.Clupeid
One caveat regarding the JSON serialization suggestion is that if you are comparing objects (not arrays) and don’t care about the order (e.g. named keys, not a numerical array), well, then JSON serialization won’t work.Clupeid
@AlanH. Do you mean JSON.stringify should work for comparing two non-Object (e.g. Number, String) arrays as well as two Object arrays, but won't for comparing two Objects? If so, why? esp. in the case of comparing two Object arrays?Hereditary
Forget arrays of objects and object arrays, whatever that means. Just think about {a: 1, b: 1} and {b: 1, a: 1}. We don’t care about order for objects, but those strings are clearly different.Clupeid
B
111

As serialization doesn't work generally (only when the order of properties matches: JSON.stringify({a:1,b:2}) !== JSON.stringify({b:2,a:1})) you have to check the count of properties and compare each property as well:

const objectsEqual = (o1, o2) =>
    Object.keys(o1).length === Object.keys(o2).length 
        && Object.keys(o1).every(p => o1[p] === o2[p]);

const obj1 = { name: 'John', age: 33};
const obj2 = { age: 33, name: 'John' };
const obj3 = { name: 'John', age: 45 };
        
console.log(objectsEqual(obj1, obj2)); // true
console.log(objectsEqual(obj1, obj3)); // false

If you need a deep comparison, you can call the function recursively:

const obj1 = { name: 'John', age: 33, info: { married: true, hobbies: ['sport', 'art'] } };
const obj2 = { age: 33, name: 'John', info: { hobbies: ['sport', 'art'], married: true } };
const obj3 = { name: 'John', age: 33 };

const objectsEqual = (o1, o2) => 
    typeof o1 === 'object' && Object.keys(o1).length > 0 
        ? Object.keys(o1).length === Object.keys(o2).length 
            && Object.keys(o1).every(p => objectsEqual(o1[p], o2[p]))
        : o1 === o2;
        
console.log(objectsEqual(obj1, obj2)); // true
console.log(objectsEqual(obj1, obj3)); // false

Then it's easy to use this function to compare objects in arrays:

const arr1 = [obj1, obj1];
const arr2 = [obj1, obj2];
const arr3 = [obj1, obj3];

const arraysEqual = (a1, a2) => 
   a1.length === a2.length && a1.every((o, idx) => objectsEqual(o, a2[idx]));

console.log(arraysEqual(arr1, arr2)); // true
console.log(arraysEqual(arr1, arr3)); // false
Buoyant answered 20/3, 2019 at 8:22 Comment(14)
Great. Just wrap the deep comparison with validation to work with null property or else return o1 === o2. Cool.Muezzin
doesn't take order into consideration. Won't work for below scenario const arr1 = [obj1, obj2]; const arr2 = [obj2, obj1];Bushy
@srikanthramesh JS objects don't define any order relation on attributes.Buoyant
Best answer and saved tons of time for me. Thank you!Lycanthrope
fails for [1,2] and [2,1]Eminence
@Eminence It's correct behavior, [1,2] and [2,1] are not equal.Buoyant
fails for multiple objects in random order in array.. .see my response pls .. I took the liberty enhancing your solution :) anyway, great job!Jemison
@Jemison An array in JS is an ordered list of items. This means the order matters and two arrays with the same items in different order are NOT the same: [1,2] not equals [2,1].Buoyant
yes ... but what I am saying is that [{id: 1, name: "jim"}, {id: 2, name: "jack"}] in some cases might be the same as [{id: 2, name: "jack"}, {id: 1, name: "jim"}] .. in my case I needed this :) that's whyJemison
@Jemison Sure, if your requirements are different that's okay. I just wanted to say, that those arrays are not the same according to the JS spec.Buoyant
It's my first week in my first job and this answer in addition to @SocratesTuas comment to make it work with null saved my life. Thank you both!Hindward
Be great to have this solution modified to work with null values in the object.Axel
Unfortunately this does not work for deep objects with arrays of objects as a property.Axel
Doesn't this approach to deep equality break on cyclic objects like let a = []; b = [a]; a.push(b); objectsEqual(a, b);Kirstinkirstyn
A
71

EDIT: You cannot overload operators in current, common browser-based implementations of JavaScript interpreters.

To answer the original question, one way you could do this, and mind you, this is a bit of a hack, simply serialize the two arrays to JSON and then compare the two JSON strings. That would simply tell you if the arrays are different, obviously you could do this to each of the objects within the arrays as well to see which ones were different.

Another option is to use a library which has some nice facilities for comparing objects - I use and recommend MochiKit.


EDIT: The answer kamens gave deserves consideration as well, since a single function to compare two given objects would be much smaller than any library to do what I suggest (although my suggestion would certainly work well enough).

Here is a naïve implemenation that may do just enough for you - be aware that there are potential problems with this implementation:

function objectsAreSame(x, y) {
   var objectsAreSame = true;
   for(var propertyName in x) {
      if(x[propertyName] !== y[propertyName]) {
         objectsAreSame = false;
         break;
      }
   }
   return objectsAreSame;
}

The assumption is that both objects have the same exact list of properties.

Oh, and it is probably obvious that, for better or worse, I belong to the only-one-return-point camp. :)

Alicealicea answered 26/8, 2008 at 1:39 Comment(4)
Just to point out the limitation: This looks like it will fail when comparing objects that contain objects. (And as you mention, it will fail when the two objects do not have “the same exact list of properties,” as y is allowed to be a super-set of x.Clupeid
One caveat regarding the JSON serialization suggestion is that if you are comparing objects (not arrays) and don’t care about the order (e.g. named keys, not a numerical array), well, then JSON serialization won’t work.Clupeid
@AlanH. Do you mean JSON.stringify should work for comparing two non-Object (e.g. Number, String) arrays as well as two Object arrays, but won't for comparing two Objects? If so, why? esp. in the case of comparing two Object arrays?Hereditary
Forget arrays of objects and object arrays, whatever that means. Just think about {a: 1, b: 1} and {b: 1, a: 1}. We don’t care about order for objects, but those strings are clearly different.Clupeid
I
23

Honestly, with 8 objects max and 8 properties max per object, your best bet is to just traverse each object and make the comparisons directly. It'll be fast and it'll be easy.

If you're going to be using these types of comparisons often, then I agree with Jason about JSON serialization...but otherwise there's no need to slow down your app with a new library or JSON serialization code.

Interdenominational answered 26/8, 2008 at 12:52 Comment(0)
F
20

I know this is an old question and the answers provided work fine ... but this is a bit shorter and doesn't require any additional libraries ( i.e. JSON ):

function arraysAreEqual(ary1,ary2){
  return (ary1.join('') == ary2.join(''));
}
Fracas answered 20/5, 2011 at 15:23 Comment(8)
The OP wanted to join arrays of objects. This only works for arrays of scalars.Eckblad
It's also fragile. If: a=["1,2"] , b=["1", "2"] then a join() on the two different arrays will result in '1,2'Sadoc
@Jason Moore not true, a.join('') // => "1,2"; b.join('') // => "12"Bifilar
You are correct about that particular example, but it's still fragile. a=["12"], b=["1", "2"] leads to "12"=="12" and I don't think any delimiter can save you because it could be in the obj itself. Nor can a length check fix it, because a=["12", "3"], b=["1", "23"]Furtado
A slightly more robust implementation: return ary1.join(',') === ary2.join(',');Septuagint
@BriceRoncace if you bothered to read the three previous comments, you'd have seen that your solution is as fragile/pointless as the one in the answer.Pasquinade
I do not understand why this answer is even having 20 votes - it does not even answer the question.Sussman
@RohanAsokan Because no one downvotes? I added mine, how about you?Estrogen
I
18

I have worked a bit on a simple algorithm to compare contents of two objects and return an intelligible list of difference. Thought I would share. It borrows some ideas for jQuery, namely the map function implementation and the object and array type checking.

It returns a list of "diff objects", which are arrays with the diff info. It's very simple.

Here it is:

// compare contents of two objects and return a list of differences
// returns an array where each element is also an array in the form:
// [accessor, diffType, leftValue, rightValue ]
//
// diffType is one of the following:
//   value: when primitive values at that index are different
//   undefined: when values in that index exist in one object but don't in 
//              another; one of the values is always undefined
//   null: when a value in that index is null or undefined; values are
//         expressed as boolean values, indicated wheter they were nulls
//   type: when values in that index are of different types; values are 
//         expressed as types
//   length: when arrays in that index are of different length; values are
//           the lengths of the arrays
//

function DiffObjects(o1, o2) {
    // choose a map() impl.
    // you may use $.map from jQuery if you wish
    var map = Array.prototype.map?
        function(a) { return Array.prototype.map.apply(a, Array.prototype.slice.call(arguments, 1)); } :
        function(a, f) { 
            var ret = new Array(a.length), value;
            for ( var i = 0, length = a.length; i < length; i++ ) 
                ret[i] = f(a[i], i);
            return ret.concat();
        };

    // shorthand for push impl.
    var push = Array.prototype.push;

    // check for null/undefined values
    if ((o1 == null) || (o2 == null)) {
        if (o1 != o2)
            return [["", "null", o1!=null, o2!=null]];

        return undefined; // both null
    }
    // compare types
    if ((o1.constructor != o2.constructor) ||
        (typeof o1 != typeof o2)) {
        return [["", "type", Object.prototype.toString.call(o1), Object.prototype.toString.call(o2) ]]; // different type

    }

    // compare arrays
    if (Object.prototype.toString.call(o1) == "[object Array]") {
        if (o1.length != o2.length) { 
            return [["", "length", o1.length, o2.length]]; // different length
        }
        var diff =[];
        for (var i=0; i<o1.length; i++) {
            // per element nested diff
            var innerDiff = DiffObjects(o1[i], o2[i]);
            if (innerDiff) { // o1[i] != o2[i]
                // merge diff array into parent's while including parent object name ([i])
                push.apply(diff, map(innerDiff, function(o, j) { o[0]="[" + i + "]" + o[0]; return o; }));
            }
        }
        // if any differences were found, return them
        if (diff.length)
            return diff;
        // return nothing if arrays equal
        return undefined;
    }

    // compare object trees
    if (Object.prototype.toString.call(o1) == "[object Object]") {
        var diff =[];
        // check all props in o1
        for (var prop in o1) {
            // the double check in o1 is because in V8 objects remember keys set to undefined 
            if ((typeof o2[prop] == "undefined") && (typeof o1[prop] != "undefined")) {
                // prop exists in o1 but not in o2
                diff.push(["[" + prop + "]", "undefined", o1[prop], undefined]); // prop exists in o1 but not in o2

            }
            else {
                // per element nested diff
                var innerDiff = DiffObjects(o1[prop], o2[prop]);
                if (innerDiff) { // o1[prop] != o2[prop]
                    // merge diff array into parent's while including parent object name ([prop])
                    push.apply(diff, map(innerDiff, function(o, j) { o[0]="[" + prop + "]" + o[0]; return o; }));
                }

            }
        }
        for (var prop in o2) {
            // the double check in o2 is because in V8 objects remember keys set to undefined 
            if ((typeof o1[prop] == "undefined") && (typeof o2[prop] != "undefined")) {
                // prop exists in o2 but not in o1
                diff.push(["[" + prop + "]", "undefined", undefined, o2[prop]]); // prop exists in o2 but not in o1

            }
        }
        // if any differences were found, return them
        if (diff.length)
            return diff;
        // return nothing if objects equal
        return undefined;
    }
    // if same type and not null or objects or arrays
    // perform primitive value comparison
    if (o1 != o2)
        return [["", "value", o1, o2]];

    // return nothing if values are equal
    return undefined;
}
Irairacund answered 19/9, 2010 at 18:32 Comment(0)
S
17

I tried JSON.stringify() and worked for me.

let array1 = [1,2,{value:'alpha'}] , array2 = [{value:'alpha'},'music',3,4];

JSON.stringify(array1) // "[1,2,{"value":"alpha"}]"

JSON.stringify(array2) // "[{"value":"alpha"},"music",3,4]"

JSON.stringify(array1) === JSON.stringify(array2); // false
Scherle answered 16/10, 2018 at 19:38 Comment(3)
To note here - this will not work if the object properties are out of orderHoeg
first we can sort the array and then use stringifyFaircloth
@Ehsansarshar that won't work... you need to sort all object properties and arrays...Pasquinade
T
7

There is a optimized code for case when function needs to equals to empty arrays (and returning false in that case)

const objectsEqual = (o1, o2) => {
    if (o2 === null && o1 !== null) return false;
    return o1 !== null && typeof o1 === 'object' && Object.keys(o1).length > 0 ?
        Object.keys(o1).length === Object.keys(o2).length && 
        Object.keys(o1).every(p => objectsEqual(o1[p], o2[p]))
        : (o1 !== null && Array.isArray(o1) && Array.isArray(o2) && !o1.length && 
        !o2.length) ? true : o1 === o2;
}
Tapetum answered 11/2, 2021 at 0:39 Comment(2)
this is fast solution ++repWaistcoat
Best solution ever, congrulations it is working truelyLymphocytosis
O
3

Here is my attempt, using Node's assert module + npm package object-hash.

I suppose that you would like to check if two arrays contain the same objects, even if those objects are ordered differently between the two arrays.

var assert = require('assert');
var hash = require('object-hash');

var obj1 = {a: 1, b: 2, c: 333},
    obj2 = {b: 2, a: 1, c: 444},
    obj3 = {b: "AAA", c: 555},
    obj4 = {c: 555, b: "AAA"};

var array1 = [obj1, obj2, obj3, obj4];
var array2 = [obj3, obj2, obj4, obj1]; // [obj3, obj3, obj2, obj1] should work as well

// calling assert.deepEquals(array1, array2) at this point FAILS (throws an AssertionError)
// even if array1 and array2 contain the same objects in different order,
// because array1[0].c !== array2[0].c

// sort objects in arrays by their hashes, so that if the arrays are identical,
// their objects can be compared in the same order, one by one
var array1 = sortArrayOnHash(array1);
var array2 = sortArrayOnHash(array2);

// then, this should output "PASS"
try {
    assert.deepEqual(array1, array2);
    console.log("PASS");
} catch (e) {
    console.log("FAIL");
    console.log(e);
}

// You could define as well something like Array.prototype.sortOnHash()...
function sortArrayOnHash(array) {
    return array.sort(function(a, b) {
        return hash(a) > hash(b);
    });
}
Ontine answered 20/3, 2017 at 12:48 Comment(0)
C
3

My practice implementation with sorting, tested and working.

const obj1 = { name: 'John', age: 33};
const obj2 = { age: 33, name: 'John' };
const obj3 = { name: 'John', age: 45 };

const equalObjs = ( obj1, obj2 ) => {
let keyExist = false;
for ( const [key, value] of Object.entries(obj1) ) {
     // Search each key in reference object and attach a callback function to 
     // compare the two object keys
    if( Object.keys(obj2).some( ( e ) => e == key ) ) {
        keyExist = true;
    }
}

return keyExist;

}


console.info( equalObjs( obj1, obj2 ) );

Compare your arrays

// Sort Arrays
    var arr1 = arr1.sort(( a, b ) => {
    var fa = Object.keys(a);
    var fb = Object.keys(b);

    if (fa < fb) {
        return -1;
    }
    if (fa > fb) {
        return 1;
    }
    return 0;
});

var arr2 = arr2.sort(( a, b ) => {
    var fa = Object.keys(a);
    var fb = Object.keys(b);

    if (fa < fb) {
        return -1;
    }
    if (fa > fb) {
        return 1;
    }
    return 0;
});

const equalArrays = ( arr1, arr2 ) => {
    // If the arrays are different length we an eliminate immediately
    if( arr1.length !== arr2.length ) {
        return false;
    } else if ( arr1.every(( obj, index ) => equalObjs( obj, arr2[index] ) ) ) {
        return true;
      } else { 
        return false;
      }
    }

    console.info( equalArrays( arr1, arr2 ) );
Crag answered 11/5, 2021 at 15:33 Comment(1)
This returns true when array diffrent .Example const obj1 = { name: 'Johnx', age: 33 } arr1.push(obj1) const obj2 = { age: 33, name: 'John' } arr2.push(obj2)Lymphocytosis
C
2

I am sharing my compare function implementation as it might be helpful for others:

 /*
  null AND null // true
  undefined AND undefined // true
  null AND undefined // false
  [] AND [] // true
  [1, 2, 'test'] AND ['test', 2, 1] // true
  [1, 2, 'test'] AND ['test', 2, 3] // false
  [undefined, 2, 'test'] AND ['test', 2, 1] // false
  [undefined, 2, 'test'] AND ['test', 2, undefined] // true
  [[1, 2], 'test'] AND ['test', [2, 1]] // true
  [1, 'test'] AND ['test', [2, 1]] // false
  [[2, 1], 'test'] AND ['test', [2, 1]] // true
  [[2, 1], 'test'] AND ['test', [2, 3]] // false
  [[[3, 4], 2], 'test'] AND ['test', [2, [3, 4]]] // true
  [[[3, 4], 2], 'test'] AND ['test', [2, [5, 4]]] // false
  [{x: 1, y: 2}, 'test'] AND ['test', {x: 1, y: 2}] // true
  1 AND 1 // true
  {test: 1} AND ['test', 2, 1] // false
  {test: 1} AND {test: 1} // true
  {test: 1} AND {test: 2} // false
  {test: [1, 2]} AND {test: [1, 2]} // true
  {test: [1, 2]} AND {test: [1]} // false
  {test: [1, 2], x: 1} AND {test: [1, 2], x: 2} // false
  {test: [1, { z: 5 }], x: 1} AND {x: 1, test: [1, { z: 5}]} // true
  {test: [1, { z: 5 }], x: 1} AND {x: 1, test: [1, { z: 6}]} // false
   */
  function is_equal(x, y) {
      const
          arr1 = x,
          arr2 = y,
          is_objects_equal = function (obj_x, obj_y) {
              if (!(
                  typeof obj_x === 'object' &&
                  Object.keys(obj_x).length > 0
              ))
                  return obj_x === obj_y;

              return Object.keys(obj_x).length === Object.keys(obj_y).length &&
                  Object.keys(obj_x).every(p => is_objects_equal(obj_x[p], obj_y[p]));
          }
          ;

      if (!( Array.isArray(arr1) && Array.isArray(arr2) ))
          return (
              arr1 && typeof arr1 === 'object' &&
              arr2 && typeof arr2 === 'object'
          )
              ? is_objects_equal(arr1, arr2)
              : arr1 === arr2;

      if (arr1.length !== arr2.length)
          return false;

      for (const idx_1 of arr1.keys())
          for (const idx_2 of arr2.keys())
              if (
                  (
                      Array.isArray(arr1[idx_1]) &&
                      this.is_equal(arr1[idx_1], arr2[idx_2])
                  ) ||
                  is_objects_equal(arr1[idx_1], arr2[idx_2])
              )
              {
                  arr2.splice(idx_2, 1);
                  break;
              }

      return !arr2.length;
  }
Canzone answered 9/11, 2021 at 10:1 Comment(0)
J
2

not sure about the performance ... will have to test on big objects .. however, this works great for me.. the advantage it has compared to the other solutions is, the objects/array do not have to be in the same order ....

it practically takes the first object in the first array, and scans the second array for every objects .. if it's a match, it will proceed to another

there is absolutely a way for optimization but it's working :)

thx to @ttulka I got inspired by his work ... just worked on it a little bit

const objectsEqual = (o1, o2) => {
  let match = false
    if(typeof o1 === 'object' && Object.keys(o1).length > 0) {
     match = (Object.keys(o1).length === Object.keys(o2).length && Object.keys(o1).every(p => objectsEqual(o1[p], o2[p])))
    }else {
     match = (o1 === o2)
    }
    return match
}

const arraysEqual = (a1, a2) => {
  let finalMatch = []
  let itemFound = []
  
  if(a1.length === a2.length) {
    finalMatch = []
    a1.forEach( i1 => {
      itemFound = []
      a2.forEach( i2 => { 
        itemFound.push(objectsEqual(i1, i2)) 
      })
        finalMatch.push(itemFound.some( i => i === true))  
    }) 
  } 
  return finalMatch.every(i => i === true)
}

const ar1 = [
  { id: 1, name: "Johnny", data: { body: "Some text"}},
  { id: 2, name: "Jimmy"}
]
const ar2 = [
  {name: "Jimmy", id: 2},
  {name: "Johnny", data: { body: "Some text"}, id: 1}
]


console.log("Match:",arraysEqual(ar1, ar2))

jsfiddle: https://jsfiddle.net/x1pubs6q/

or just use lodash :))))

const _ = require('lodash')

const isArrayEqual = (x, y) => {
  return _.isEmpty(_.xorWith(x, y, _.isEqual));
};
Jemison answered 9/12, 2021 at 8:14 Comment(1)
Fantastic, exactly what I was looking for!Await
C
1

The objectsAreSame function mentioned in @JasonBunting's answer works fine for me. However, there's a little problem: If x[propertyName] and y[propertyName] are objects (typeof x[propertyName] == 'object'), you'll need to call the function recursively in order to compare them.

Caldera answered 16/3, 2009 at 6:40 Comment(0)
M
1

Please try this one:

function used_to_compare_two_arrays(a, b)
{
  // This block will make the array of indexed that array b contains a elements
  var c = a.filter(function(value, index, obj) {
    return b.indexOf(value) > -1;
  });

  // This is used for making comparison that both have same length if no condition go wrong 
  if (c.length !== a.length) {
    return 0;
  } else{
    return 1;
  }
}
Marilynnmarimba answered 11/8, 2014 at 6:51 Comment(1)
uhm... the if statement can be simplified to just return c.length === a.length;Pasquinade
G
0

There`s my solution. It will compare arrays which also have objects and arrays. Elements can be stay in any positions. Example:

const array1 = [{a: 1}, {b: 2}, { c: 0, d: { e: 1, f: 2, } }, [1,2,3,54]];
const array2 = [{a: 1}, {b: 2}, { c: 0, d: { e: 1, f: 2, } }, [1,2,3,54]];

const arraysCompare = (a1, a2) => {
  if (a1.length !== a2.length) return false;
  const objectIteration = (object) => {
    const result = [];
    const objectReduce = (obj) => {
      for (let i in obj) {
        if (typeof obj[i] !== 'object') {
          result.push(`${i}${obj[i]}`);
        } else {
          objectReduce(obj[i]);
        }
      }
    };
    objectReduce(object);
    return result;
  };
  const reduceArray1 = a1.map(item => {
    if (typeof item !== 'object') return item;
    return objectIteration(item).join('');
  });
  const reduceArray2 = a2.map(item => {
    if (typeof item !== 'object') return item;
    return objectIteration(item).join('');
  });
  const compare =  reduceArray1.map(item => reduceArray2.includes(item));
  return compare.reduce((acc, item) => acc + Number(item)) === a1.length;
};

console.log(arraysCompare(array1, array2));
Godlike answered 14/2, 2021 at 19:7 Comment(0)
G
0

This is work for me to compare two array of objects without taking into consideration the order of the items

const collection1 =  [
  { id: "1", name: "item 1", subtitle: "This is a subtitle", parentId: "1" },
  { id: "2", name: "item 2", parentId: "1" },
  { id: "3", name: "item 3", parentId: "1" },
]
const collection2 =  [
  { id: "3", name: "item 3", parentId: "1" },
  { id: "2", name: "item 2", parentId: "1" },
  { id: "1", name: "item 1", subtitle: "This is a subtitle", parentId: "1" },
]


const contains = (arr, obj) => {
  let i = arr.length;
  while (i--) {
     if (JSON.stringify(arr[i]) === JSON.stringify(obj)) {
         return true;
     }
  }
  return false;
}

const isEqual = (obj1, obj2) => {
  let n = 0
  if (obj1.length !== obj2.length) {
      return false;
  }
  for (let i = 0; i < obj1.length; i++) {
      if (contains(obj2, obj1[i])) {
        n++
      }
  }
  return n === obj1.length
}

console.log(isEqual(collection1,collection2))

if you take into consideration the order of the items use built in function in lodash isEqual

Glyptograph answered 20/6, 2022 at 18:36 Comment(2)
You may want to JSON.stringify(obj) only one time and test against it instead of everytime.Lamarckism
Change one of your objects to have a different order (e.g. { parentId, name, id }) and watch this break..Estrogen
V
0

To compare two arrays of objects efficiently, you can:

  1. Convert objects to strings: Convert each object in both arrays to a string representation using JSON.stringify(). This allows for easy comparison.

Here's a JavaScript function that implements this approach:

function areArraysEqual(arr1, arr2) {
    // Check if arrays have the same length
    if (arr1.length !== arr2.length) {
        return false;
    }

    // Sort arrays to ensure order doesn't affect the comparison
    const sortedArr1 = arr1.slice().sort();
    const sortedArr2 = arr2.slice().sort();

    // Convert objects to strings and compare
    for (let i = 0; i < sortedArr1.length; i++) {
        const obj1String = JSON.stringify(sortedArr1[i]);
        const obj2String = JSON.stringify(sortedArr2[i]);

        // If any objects are different, return false
        if (obj1String !== obj2String) {
            return false;
        }
    }

    // If all objects are the same, return true
    return true;
}

// Example usage
const arr1 = [{a: 1}, {b: 2}, {c: 3}];
const arr2 = [{b: 2}, {c: 3}, {a: 1}];
console.log(areArraysEqual(arr1, arr2)); // Output: true

This function areArraysEqual compares two arrays of objects efficiently by sorting them, converting each object to a string, and then comparing the string representations. If the arrays contain the same objects regardless of their order, the function returns true; otherwise, it returns false.

Vichyssoise answered 11/4 at 19:23 Comment(0)
G
-1

comparing with json is pretty bad. try this package to compare nested arrays and get the difference.

https://www.npmjs.com/package/deep-object-diff

Genipap answered 30/1, 2021 at 8:42 Comment(1)
This is a link to an answer. It would be better if it showed how to use the library linked to to solve the problem the OP presents.Estrogen
C
-2

using _.some from lodash: https://lodash.com/docs/4.17.11#some

const array1AndArray2NotEqual = 
          _.some(array1, (a1, idx) => a1.key1 !== array2[idx].key1 
                                     || a1.key2 !== array2[idx].key2 
                                     || a1.key3 !== array2[idx].key3);
Carpal answered 3/1, 2019 at 23:24 Comment(0)
O
-3

If you stringify them...

type AB = {
  nome: string;
}

const a: AB[] = [{ nome: 'Célio' }];
const b: AB[] = [{ nome: 'Célio' }];

console.log(a === b); // false
console.log(JSON.stringify(a) === JSON.stringify(b)); // true

Onionskin answered 3/7, 2022 at 12:1 Comment(2)
For a simple object with a single property with a primitive value, this does indeed work. Try it with two arrays with objects with more than one property in different order (e.g. const a = [{ nome: 'Célio', age: 20 }]; const b = [{ age: 20, nome: 'Célio' }]) and you'll find it no longer works. This is discussed in several of the earlier answers that attempted the same trick (e.g. stackoverflow.com/a/52842903)Estrogen
this wont work if the order of data on both array of objects are different.Hide

© 2022 - 2024 — McMap. All rights reserved.