How to compare arrays in JavaScript?

ID : 976

viewed : 185

Tags : javascriptarraysjsonjavascript





Top 5 Answer for How to compare arrays in JavaScript?

vote vote

97

To compare arrays, loop through them and compare every value:

Comparing arrays:

// Warn if overriding existing method if(Array.prototype.equals)     console.warn("Overriding existing Array.prototype.equals. Possible causes: New API defines the method, there's a framework conflict or you've got double inclusions in your code."); // attach the .equals method to Array's prototype to call it on any array Array.prototype.equals = function (array) {     // if the other array is a falsy value, return     if (!array)         return false;      // compare lengths - can save a lot of time      if (this.length != array.length)         return false;      for (var i = 0, l=this.length; i < l; i++) {         // Check if we have nested arrays         if (this[i] instanceof Array && array[i] instanceof Array) {             // recurse into the nested arrays             if (!this[i].equals(array[i]))                 return false;                }                    else if (this[i] != array[i]) {              // Warning - two different object instances will never be equal: {x:20} != {x:20}             return false;            }                }            return true; } // Hide method from for-in loops Object.defineProperty(Array.prototype, "equals", {enumerable: false}); 

Usage:

[1, 2, [3, 4]].equals([1, 2, [3, 2]]) === false; [1, "2,3"].equals([1, 2, 3]) === false; [1, 2, [3, 4]].equals([1, 2, [3, 4]]) === true; [1, 2, 1, 2].equals([1, 2, 1, 2]) === true; 

You may say "But it is much faster to compare strings - no loops..." well, then you should note there ARE loops. First recursive loop that converts Array to string and second, that compares two strings. So this method is faster than use of string.

I believe that larger amounts of data should be always stored in arrays, not in objects. However if you use objects, they can be partially compared too.
Here's how:

Comparing objects:

I've stated above, that two object instances will never be equal, even if they contain same data at the moment:

({a:1, foo:"bar", numberOfTheBeast: 666}) == ({a:1, foo:"bar", numberOfTheBeast: 666})  //false 

This has a reason, since there may be, for example private variables within objects.

However, if you just use object structure to contain data, comparing is still possible:

Object.prototype.equals = function(object2) {     //For the first loop, we only check for types     for (propName in this) {         //Check for inherited methods and properties - like .equals itself         //https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty         //Return false if the return value is different         if (this.hasOwnProperty(propName) != object2.hasOwnProperty(propName)) {             return false;         }         //Check instance type         else if (typeof this[propName] != typeof object2[propName]) {             //Different types => not equal             return false;         }     }     //Now a deeper check using other objects property names     for(propName in object2) {         //We must check instances anyway, there may be a property that only exists in object2             //I wonder, if remembering the checked values from the first loop would be faster or not          if (this.hasOwnProperty(propName) != object2.hasOwnProperty(propName)) {             return false;         }         else if (typeof this[propName] != typeof object2[propName]) {             return false;         }         //If the property is inherited, do not check any more (it must be equa if both objects inherit it)         if(!this.hasOwnProperty(propName))           continue;                  //Now the detail check and recursion                  //This returns the script back to the array comparing         /**REQUIRES Array.equals**/         if (this[propName] instanceof Array && object2[propName] instanceof Array) {                    // recurse into the nested arrays            if (!this[propName].equals(object2[propName]))                         return false;         }         else if (this[propName] instanceof Object && object2[propName] instanceof Object) {                    // recurse into another objects                    //console.log("Recursing to compare ", this[propName],"with",object2[propName], " both named \""+propName+"\"");            if (!this[propName].equals(object2[propName]))                         return false;         }         //Normal value comparison for strings and numbers         else if(this[propName] != object2[propName]) {            return false;         }     }     //If everything passed, let's say YES     return true; }   

However, remember that this one is to serve in comparing JSON like data, not class instances and other stuff. If you want to compare more complicated objects, look at this answer and it's super long function.
To make this work with Array.equals you must edit the original function a little bit:

...     // Check if we have nested arrays     if (this[i] instanceof Array && array[i] instanceof Array) {         // recurse into the nested arrays         if (!this[i].equals(array[i]))             return false;     }     /**REQUIRES OBJECT COMPARE**/     else if (this[i] instanceof Object && array[i] instanceof Object) {         // recurse into another objects         //console.log("Recursing to compare ", this[propName],"with",object2[propName], " both named \""+propName+"\"");         if (!this[i].equals(array[i]))             return false;         }     else if (this[i] != array[i]) { ... 

I made a little test tool for both of the functions.

Bonus: Nested arrays with indexOf and contains

Samy Bencherif has prepared useful functions for the case you're searching for a specific object in nested arrays, which are available here: https://jsfiddle.net/SamyBencherif/8352y6yw/

vote vote

82

While this only works for scalar arrays (see note below), it is short:

array1.length === array2.length && array1.every(function(value, index) { return value === array2[index]}) 

Rr, in ECMAScript 6 / CoffeeScript / TypeScript with Arrow Functions:

array1.length === array2.length && array1.every((value, index) => value === array2[index]) 

(Note: 'scalar' here means values that can be compared directly using === . So: numbers, strings, objects by reference, functions by reference. See the MDN reference for more info about the comparison operators).

UPDATE

From what I read from the comments, sorting the array and comparing may give accurate result:

const array2Sorted = array2.slice().sort(); array1.length === array2.length && array1.slice().sort().every(function(value, index) {     return value === array2Sorted[index]; }); 

Eg:

array1 = [2,3,1,4]; array2 = [1,2,3,4]; 

Then the above code would give true

vote vote

79

I like to use the Underscore library for array/object heavy coding projects ... in Underscore and Lodash whether you're comparing arrays or objects it just looks like this:

_.isEqual(array1, array2)   // returns a boolean _.isEqual(object1, object2) // returns a boolean 
vote vote

70

This I think is the simplest way to do it using JSON stringify, and it may be the best solution in some situations:

JSON.stringify(a1) === JSON.stringify(a2); 

This converts the objects a1 and a2 into strings so they can be compared. The order is important in most cases, for that can sort the object using a sort algorithm shown in one of the above answers.

Please do note that you are no longer comparing the object but the string representation of the object. It may not be exactly what you want.

vote vote

52

In the spirit of the original question:

I'd like to compare two arrays... ideally, efficiently. Nothing fancy, just true if they are identical, and false if not.

I have been running performance tests on some of the more simple suggestions proposed here with the following results (fast to slow):

while (67%) by Tim Down

var i = a1.length; while (i--) {     if (a1[i] !== a2[i]) return false; } return true 

every (69%) by user2782196

a1.every((v,i)=> v === a2[i]); 

reduce (74%) by DEIs

a1.reduce((a, b) => a && a2.includes(b), true); 

join & toString (78%) by Gaizka Allende & vivek

a1.join('') === a2.join('');  a1.toString() === a2.toString(); 

half toString (90%) by Victor Palomo

a1 == a2.toString(); 

stringify (100%) by radtek

JSON.stringify(a1) === JSON.stringify(a2); 

Note the examples below assumes the arrays are sorted, single-dimensional arrays. .length comparison has been removed for a common benchmark (add a1.length === a2.length to any of the suggestions and you will get a ~10% performance boost). Choose whatever solutions that works best for you knowing the speed and limitation of each.

Unrelated note: it is interesting to see people getting all trigger-happy John Waynes on the down vote button on perfectly legitimate answers to this question.

Top 3 video Explaining How to compare arrays in JavaScript?







Related QUESTION?