Using jQuery to compare two arrays of Javascript objects

JavascriptJqueryArraysObjectCompare

Javascript Problem Overview


I have two arrays of JavaScript Objects that I'd like to compare to see if they are the same. The objects may not (and most likely will not) be in the same order in each array. Each array shouldn't have any more than 10 objects. I thought jQuery might have an elegant solution to this problem, but I wasn't able to find much online.

I know that a brute nested $.each(array, function(){}) solution could work, but is there any built in function that I'm not aware of?

Thanks.

Javascript Solutions


Solution 1 - Javascript

There is an easy way...

$(arr1).not(arr2).length === 0 && $(arr2).not(arr1).length === 0

If the above returns true, both the arrays are same even if the elements are in different order.

NOTE: This works only for jquery versions < 3.0.0 when using JSON objects

Solution 2 - Javascript

I was also looking for this today and found: http://www.breakingpar.com/bkp/home.nsf/0/87256B280015193F87256BFB0077DFFD

Don't know if that's a good solution though they do mention some performance considerations taken into account.

I like the idea of a jQuery helper method. @David I'd rather see your compare method to work like:

jQuery.compare(a, b)

I doesn't make sense to me to be doing:

$(a).compare(b)

where a and b are arrays. Normally when you $(something) you'd be passing a selector string to work with DOM elements.

Also regarding sorting and 'caching' the sorted arrays:

  • I don't think sorting once at the start of the method instead of every time through the loop is 'caching'. The sort will still happen every time you call compare(b). That's just semantics, but...
  • for (var i = 0; t[i]; i++) { ...this loop finishes early if your t array contains a false value in it somewhere, so $([1, 2, 3, 4]).compare([1, false, 2, 3]) returns true!
  • More importantly the array sort() method sorts the array in place, so doing var b = t.sort() ...doesn't create a sorted copy of the original array, it sorts the original array and also assigns a reference to it in b. I don't think the compare method should have side-effects.

It seems what we need to do is to copy the arrays before working on them. The best answer I could find for how to do that in a jQuery way was by none other than John Resig here on SO! https://stackoverflow.com/questions/122102/what-is-the-most-efficient-way-to-clone-a-javascript-object/122704#122704 (see comments on his answer for the array version of the object cloning recipe)

In which case I think the code for it would be:

jQuery.extend({
    compare: function (arrayA, arrayB) {
        if (arrayA.length != arrayB.length) { return false; }
        // sort modifies original array
        // (which are passed by reference to our method!)
        // so clone the arrays before sorting
        var a = jQuery.extend(true, [], arrayA);
        var b = jQuery.extend(true, [], arrayB);
        a.sort(); 
        b.sort();
        for (var i = 0, l = a.length; i < l; i++) {
            if (a[i] !== b[i]) { 
                return false;
            }
        }
        return true;
    }
});

var a = [1, 2, 3];
var b = [2, 3, 4];
var c = [3, 4, 2];

jQuery.compare(a, b);
// false

jQuery.compare(b, c);
// true

// c is still unsorted [3, 4, 2]

Solution 3 - Javascript

My approach was quite different - I flattened out both collections using JSON.stringify and used a normal string compare to check for equality.

I.e.

var arr1 = [             {Col: 'a', Val: 1},              {Col: 'b', Val: 2},              {Col: 'c', Val: 3}           ];

var arr2 = [             {Col: 'x', Val: 24},              {Col: 'y', Val: 25},              {Col: 'z', Val: 26}           ];

if(JSON.stringify(arr1) == JSON.stringify(arr2)){
    alert('Collections are equal');
}else{
    alert('Collections are not equal');
}

NB: Please note that his method assumes that both Collections are sorted in a similar fashion, if not, it would give you a false result!

Solution 4 - Javascript

Convert both array to string and compare

if (JSON.stringify(array1) == JSON.stringify(array2))
{
    // your code here
}

Solution 5 - Javascript

I found this discussion because I needed a way to deep compare arrays and objects. Using the examples here, I came up with the following (broken up into 3 methods for clarity):

jQuery.extend({
    compare : function (a,b) {
        var obj_str = '[object Object]',
            arr_str = '[object Array]',
            a_type  = Object.prototype.toString.apply(a),
            b_type  = Object.prototype.toString.apply(b);
        
            if ( a_type !== b_type) { return false; }
            else if (a_type === obj_str) {
                return $.compareObject(a,b);
            }
            else if (a_type === arr_str) {
                return $.compareArray(a,b);
            }
            return (a === b);
        }
});

jQuery.extend({
    compareArray: function (arrayA, arrayB) {
        var a,b,i,a_type,b_type;
        // References to each other?
        if (arrayA === arrayB) { return true;}
        
        if (arrayA.length != arrayB.length) { return false; }
        // sort modifies original array
        // (which are passed by reference to our method!)
        // so clone the arrays before sorting
        a = jQuery.extend(true, [], arrayA);
        b = jQuery.extend(true, [], arrayB);
        a.sort(); 
        b.sort();
        for (i = 0, l = a.length; i < l; i+=1) {
            a_type = Object.prototype.toString.apply(a[i]);
            b_type = Object.prototype.toString.apply(b[i]);
            
            if (a_type !== b_type) {
                return false;
            }
            
            if ($.compare(a[i],b[i]) === false) {
                return false;
            }
        }
        return true;
    }
});

jQuery.extend({
    compareObject : function(objA,objB) {

        var i,a_type,b_type;

        // Compare if they are references to each other 
        if (objA === objB) { return true;}
        
        if (Object.keys(objA).length !== Object.keys(objB).length) { return false;}
        for (i in objA) {
            if (objA.hasOwnProperty(i)) {
                if (typeof objB[i] === 'undefined') {
                    return false;
                }
                else {
                    a_type = Object.prototype.toString.apply(objA[i]);
                    b_type = Object.prototype.toString.apply(objB[i]);
                
                    if (a_type !== b_type) {
                        return false; 
                    }
                }
            }
            if ($.compare(objA[i],objB[i]) === false){
                return false;
            }
        }
        return true;
    }
});

Testing

var a={a : {a : 1, b: 2}},
    b={a : {a : 1, b: 2}},
    c={a : {a : 1, b: 3}},
    d=[1,2,3],
    e=[2,1,3];

console.debug('a and b = ' + $.compare(a,b)); // a and b = true
console.debug('b and b = ' + $.compare(b,b)); // b and b = true
console.debug('b and c = ' + $.compare(b,c)); // b and c = false
console.debug('c and d = ' + $.compare(c,d)); // c and d = false
console.debug('d and e = ' + $.compare(d,e)); // d and e = true

Solution 6 - Javascript

In my case compared arrays contain only numbers and strings. This solution worked for me:

function are_arrs_equal(arr1, arr2){
    return arr1.sort().toString() === arr2.sort().toString()
}

Let's test it!

arr1 = [1, 2, 3, 'nik']
arr2 = ['nik', 3, 1, 2]
arr3 = [1, 2, 5]

console.log (are_arrs_equal(arr1, arr2)) //true
console.log (are_arrs_equal(arr1, arr3)) //false

Solution 7 - Javascript

I don't think there's a good "jQuery " way to do this, but if you need efficiency, map one of the arrays by a certain key (one of the unique object fields), and then do comparison by looping through the other array and comparing against the map, or associative array, you just built.

If efficiency is not an issue, just compare every object in A to every object in B. As long as |A| and |B| are small, you should be okay.

Solution 8 - Javascript

Well, if you want to compare only the contents of arrays, there's a useful jQuery function $.inArray()

var arr = [11, "String #1", 14, "String #2"];
var arr_true = ["String #1", 14, "String #2", 11]; // contents are the same as arr
var arr_false = ["String #1", 14, "String #2", 16]; // contents differ

function test(arr_1, arr_2) {
    var equal = arr_1.length == arr_2.length; // if array sizes mismatches, then we assume, that they are not equal
    if (equal) {
        $.each(arr_1, function (foo, val) {
            if (!equal) return false;
            if ($.inArray(val, arr_2) == -1) {
                equal = false;
            } else {
                equal = true;
            }
        });
    }
    return equal;
}

alert('Array contents are the same? ' + test(arr, arr_true)); //- returns true
alert('Array contents are the same? ' + test(arr, arr_false)); //- returns false

Solution 9 - Javascript

The nice one liner from https://stackoverflow.com/a/7726509/1251219">Sudhakar R as jQuery global method.

/**
 * Compare two arrays if they are equal even if they have different order.
 *
 * @link https://stackoverflow.com/a/7726509
 */
jQuery.extend({
  /**
   * @param {array} a
   *   First array to compare.
   * @param {array} b
   *   Second array to compare.
   * @return {boolean}
   *   True if both arrays are equal, otherwise false.
   */
  arrayCompare: function (a, b) {
    return $(a).not(b).get().length === 0 && $(b).not(a).get().length === 0;
  }
});

Solution 10 - Javascript

Change array to string and compare

var arr = [1,2,3], 
arr2 = [1,2,3]; 
console.log(arr.toString() === arr2.toString());

Solution 11 - Javascript

I also found this when looking to do some array comparisons with jQuery. In my case I had strings which I knew to be arrays:

var needle = 'apple orange';
var haystack = 'kiwi orange banana apple plum';

But I cared if it was a complete match or only a partial match, so I used something like the following, based off of Sudhakar R's answer:

function compareStrings( needle, haystack ){
  var needleArr = needle.split(" "),
    haystackArr = haystack.split(" "),
    compare = $(haystackArr).not(needleArr).get().length;
  
  if( compare == 0 ){
    return 'all';
  } else if ( compare == haystackArr.length  ) {
    return 'none';
  } else {
    return 'partial';
  }
}

Solution 12 - Javascript

If duplicates matter such that [1, 1, 2] should not be equal to [2, 1] but should equal [1, 2, 1], here is a reference counting solution:

  const arrayContentsEqual = (arrayA, arrayB) => {
    if (arrayA.length !== arrayB.length) {
      return false}

    const refCount = (function() {
      const refCountMap = {};
      const refCountFn = (elt, count) => {
          refCountMap[elt] = (refCountMap[elt] || 0) + count}
      refCountFn.isZero = () => {
        for (let elt in refCountMap) {
          if (refCountMap[elt] !== 0) {
            return false}}
        return true}
      return refCountFn})()

    arrayB.map(eltB => refCount(eltB, 1));
    arrayA.map(eltA => refCount(eltA, -1));
    return refCount.isZero()}

Here is the fiddle to play with.

Solution 13 - Javascript

var arr1 = [
             {name: 'a', Val: 1}, 
             {name: 'b', Val: 2}, 
             {name: 'c', Val: 3}
           ];

var arr2 = [
             {name: 'c', Val: 3},
             {name: 'x', Val: 4}, 
             {name: 'y', Val: 5}, 
             {name: 'z', Val: 6}
           ];
var _isEqual = _.intersectionWith(arr1, arr2, _.isEqual);// common in both array
var _difference1 = _.differenceWith(arr1, arr2, _.isEqual);//difference from array1 
var _difference2 = _.differenceWith(arr2, arr1, _.isEqual);//difference from array2 
console.log(_isEqual);// common in both array
console.log(_difference1);//difference from array1 
console.log(_difference2);//difference from array2 

<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.js"></script>

Solution 14 - Javascript

Try this

function check(c,d){
  var a = c, b = d,flg = 0;
  if(a.length == b.length) 
  { 
     for(var i=0;i<a.length;i++) 
           a[i] != b[i] ? flg++ : 0; 
  } 
  else  
  { 
     flg = 1; 
  } 
  return flg = 0;
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMegaMattView Question on Stackoverflow
Solution 1 - JavascriptsuDockerView Answer on Stackoverflow
Solution 2 - JavascriptAnentropicView Answer on Stackoverflow
Solution 3 - JavascriptKwexView Answer on Stackoverflow
Solution 4 - JavascriptgmsiView Answer on Stackoverflow
Solution 5 - JavascriptVinny AlvesView Answer on Stackoverflow
Solution 6 - JavascriptyesnikView Answer on Stackoverflow
Solution 7 - JavascriptStefan KendallView Answer on Stackoverflow
Solution 8 - JavascriptVilius PaulauskasView Answer on Stackoverflow
Solution 9 - JavascriptFleshgrinderView Answer on Stackoverflow
Solution 10 - JavascriptjayView Answer on Stackoverflow
Solution 11 - JavascriptBungView Answer on Stackoverflow
Solution 12 - JavascriptPaul WhippView Answer on Stackoverflow
Solution 13 - JavascriptParth RavalView Answer on Stackoverflow
Solution 14 - JavascriptExceptionView Answer on Stackoverflow