1

I am trying to compare two array of objects. Below is my code.

var result = identical([
    {"depid": "100", "depname": ""},
    {"city": "abc", "state": "xyz"},
    {"firstName": "John", "lastName": "Doe", "contactno": {"ph": 12345, "mob": 485428428}}
], [
    {"firstName": "John", "lastName": "Doe", "contactno": {"ph": 12345, "mob": 485428428}},
    {"depid": "100", "depname": ""},
    {"city": "abc", "state": "xyz"}
]);

console.log(result); // returns false

function identical(a, b) {
    function sort(object) {
      if (typeof object !== "object" || object === null) {
            return object;
        }
        return Object.keys(object).sort().map(function (key) {
            return {
                key: key,
                value: sort(object[key])
            };
        });
    }

    return JSON.stringify(sort(a)) === JSON.stringify(sort(b));
};

I want to know why I am getting result as false while comparing the above two array of objects.

If I pass the below object, the result is true

var result = identical([
    {"firstName": "John", "lastName": "Doe", "contactno": {"ph": 12345, "mob": 485428428}},
    {"depid": "100", "depname": ""},
    {"city": "abc", "state": "xyz"}
], [
    {"firstName": "John", "lastName": "Doe", "contactno": {"ph": 12345, "mob": 485428428}},
    {"depid": "100", "depname": ""},
    {"city": "abc", "state": "xyz"}
]);

How to compare based on keys alone and without seeing the order of objects ?

user4324324
  • 559
  • 3
  • 7
  • 25

3 Answers3

3

One of the solutions I found, is to define a function to test the equality of the objects, and then you need to call that function for each element on the array. this code works fine for me:

Object.prototype.equals = function(x) {
        for(p in this) {
            switch(typeof(this[p])) {
                    case 'object':
                            if (!this[p].equals(x[p])) { return false }; break;
                    case 'function':
                            if (typeof(x[p])=='undefined' || (p != 'equals' && this[p].toString() != x[p].toString())) { return false; }; break;
                    default:
                            if (this[p] != x[p]) { return false; }
            }
        }
        for(p in x) {
            if(typeof(this[p])=='undefined') {return false;}
        }

        return true;
    }

Source : Object comparison in JavaScript

    function identical (arr1, arr2) {

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

        var exists = arr1.length;
        for(var i = 0; i<arr1.length; i++) {
            for(var j =0; j<arr2.length ; j++) {
                if(Object.keys(arr1[i]).equals(Object.keys(arr2[j]))) {
                   exists--;
                }
            }
        }

        return !exists;
    }

Now the result of this code is true

var result = identical([
    {"firstName": "John", "lastName": "Doe", "contactno": {"ph": 12345, "mob": 485428428}},
    {"depid": "100", "depname": ""},
    {"city": "abc", "state": "xyz"}
], [
    {"firstName": "John", "lastName": "Doe", "contactno": {"ph": 12345, "mob": 485428428}},
    {"depid": "100", "depname": ""},
    {"city": "abc", "state": "xyz"}
]);

Edit :

To compare only keys, you need to use :

Object.keys(arr1[i]).equals(Object.keys(arr2[j])

instead of

arr1[i].equals(arr2[j])

I made the update on the code above.

Community
  • 1
  • 1
Khalid
  • 4,730
  • 5
  • 27
  • 50
  • Thanks for the solution. But I dont want to check the values. Even this object must return true since keys are same var result = identical([ {"depid": "100", "depname": "role"}, {"city": "abc", "state": "xyz"}, {"firstName": "John", "lastName": "Doe", "contactno": {"ph": 12345, "mob": 485428428}} ], [ {"firstName": "John", "lastName": "Doe", "contactno": {"ph": 12345, "mob": 485428428}}, {"depid": "100", "depname": ""}, {"city": "abc", "state": "xyz"} ]); – user4324324 Mar 17 '15 at 15:56
  • I didn't understand, the values you're passing to the function don't have identical values, do you mean, you need to check only keys ? – Khalid Mar 17 '15 at 16:38
  • Yes. Comparing only the keys. – user4324324 Mar 17 '15 at 16:40
  • Awesome update. It works! I accept your answer. One more help, any idea on how to update the values of object2 in object1. – user4324324 Mar 18 '15 at 10:46
  • can you explain more what you want to do ? do you mean cloning an object into another one ? – Khalid Mar 18 '15 at 10:52
  • If I pass this object. var result = identical([ {"firstName": "John", "lastName": "Doe", "contactno": {"ph": 12345, "mobile": 485428428}} ], [ {"firstName": "John", "lastName": "Doe", "contactno": {"ph": 12345, "mob": 485428428}} ]); Your code is failing. Any idea why? I think only root level comparison is happening – user4324324 Mar 18 '15 at 10:59
1

While serializing objects to string the keys aren't guaranteed to be in same order. To compare irrespective of order check this Comparing two json arrays

Community
  • 1
  • 1
meteor
  • 2,518
  • 4
  • 38
  • 52
1

It fails because a is an array, so sort(a) sorts a with respect to the array indexes. You can try:

 var l = ['a','b'];
 alert(Object.keys(l));

it shows:

0,1

So sort(a) sorts don't put the objects inside in a meaningful order. It does not even care about what is in the array.

It you want to compare arrays of objects, I would suggest to use your function sort on each object of the array, then jsonify each object in the array, then sort the array of strings and compare the two resulting sorted arrays of strings.

Nytux
  • 358
  • 1
  • 9