1512

I'd like to compare two arrays... ideally, efficiently. Nothing fancy, just true if they are identical, and false if not. Not surprisingly, the comparison operator doesn't seem to work.

var a1 = [1,2,3];
var a2 = [1,2,3];
console.log(a1==a2);    // Returns false
console.log(JSON.stringify(a1)==JSON.stringify(a2));    // Returns true

JSON encoding each array does, but is there a faster or "better" way to simply compare arrays without having to iterate through each value?

Mulan
  • 129,518
  • 31
  • 228
  • 259
Julian H. Lam
  • 25,501
  • 13
  • 46
  • 73
  • 11
    You could first compare their length, and if they are equal each values. – TJHeuvel Oct 20 '11 at 14:29
  • 74
    What makes two arrays equal for you? Same elements? Same order of elements? Encoding as JSON only works as long as the element of the array can be serialized to JSON. If the array can contain objects, how deep would you go? When are two objects "equal"? – Felix Kling Oct 20 '11 at 14:31
  • 1
    Possible duplicate http://stackoverflow.com/questions/27030/comparing-arrays-of-objects-in-javascript – RHT Oct 20 '11 at 14:33
  • @Blender - possibly, but the examples I did find on SO were only to specifically *do* something with the arrays, such as outputting all of the elements present in one but not the other, which would entail iterating through each element. Felix, in this case, same elements in the same order. – Julian H. Lam Oct 20 '11 at 14:33
  • 89
    @FelixKling, defining "equality" is definitely a subtle topic, but for people coming to JavaScript from higher-level languages, there is no excuse for silliness like `([] == []) == false`. – Alex D Mar 16 '14 at 17:52
  • possible duplicate of [How to check identical array in most efficient way?](http://stackoverflow.com/questions/4025893/how-to-check-identical-array-in-most-efficient-way) – Palec Jun 24 '14 at 15:10
  • 8
    @AlexD it looks like arrays use reference equality which is what you'd expect. It'd be pretty awful if you couldn't do that – JonnyRaa Aug 29 '14 at 08:24
  • 7
    @AlexD I somewhat can't think of a language where this doesn't happen. In C++, you'd be comparing two pointers - false. In Java, you're doing the same as in javascript. In PHP, something behind the scenes will loop through the arrays - do you call PHP a Higher level language? – Tomáš Zato Aug 30 '14 at 01:33
  • [2, 1].toSTring() == [2, 1].toString() – Bart Hoekstra Jun 13 '16 at 11:23
  • 1
    `[1, 2].join() === [1, 2].join()` – Andre Figueiredo Jul 26 '18 at 22:04
  • 2
    I say if you're not working with HUGE datasets where you'd be able to measure a 1s or higher reduction in speed, stick with what your'e doing now. Since I don't do anything mission critical with JS, I usually just do this: `if (a1.length!==a2.length || JSON.stringify(a1)!==JSON.stringify(a2)) { /* something is different */ }` – thdoan Sep 19 '18 at 21:24
  • `JSON.parse` would also iterate through each value anyway so I guess it would be better to compare iterating through each value and reduce some steps of execution ( like encoding it into JSON ). – Birey Oct 20 '11 at 14:32
  • 2
    @TomášZato-ReinstateMonica I almost agree, other than there are two different equality operators in js. In Python you have `is` and `==`, which do "what you'd expect them to do," one checks reference equality, and the other uses either built-in or overloaded comparison. In my opinion it's far more intuitive and useful than the js state of affairs. – Nathan Chappell Aug 25 '20 at 11:02
  • 1
    Once the [records and tuples proposal](//github.com/tc39/proposal-record-tuple) gets accepted, you can compare tuples instead: `#[1, 2, 3] === #[1, 2, 3]`. – Sebastian Simon Jun 03 '21 at 19:10
  • For reference in Ruby `[1,2,3] == [1,2,3] # returns true`. I guess it just comes down to understanding the nuances of each language. – Clark Taylor Sep 05 '22 at 18:17

56 Answers56

1066

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;
    // if the argument is the same array, we can be sure the contents are same as well
    if(array === this)
        return true;
    // 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/

Tomáš Zato
  • 50,171
  • 52
  • 268
  • 778
  • 3
    Thanks for your input. Given its view count, I suppose many users redirected here from Google are having the same conundrum of figuring out exactly how to compare two arrays "properly"! – Julian H. Lam Feb 13 '13 at 16:05
  • 36
    If you want to do strict comparisons use `this[i] !== array[i]` instead of `!=`. – Tim S. May 15 '13 at 13:19
  • 42
    Your method should be called `equals` instead of `compare`. At least in .NET, compare usually returns a signed int indicating which object is greater than the other. See: [Comparer.Compare](http://msdn.microsoft.com/en-us/library/2y07t0wt%28v=vs.110%29.aspx). – Oliver May 31 '13 at 12:24
  • It fails on comparing arrays with the same values but different order. Please check my suggestion http://stackoverflow.com/a/16944097/1494393 – Igor S. Jun 05 '13 at 15:38
  • 7
    +1 for the answer and a beer to your health for writing the function in the array prototype. – Luca Fagioli Jun 07 '13 at 12:39
  • 4
    Nice answer... but shouldn't you be caching the array length for the loop: `for (var i = 0, len = this.length; i < len; i++)` – Pete Sep 19 '13 at 10:34
  • 17
    Nt only is this the right way of doing it, it's also considerable more efficent. Here's a quick jsperf script I prepared for all the methods suggested in this question. http://jsperf.com/comparing-arrays2 – Tolga E Oct 16 '13 at 19:30
  • 3
    So actually, placing the function on the array prototype is probably not the right thing to do. Messing with the global objects like this can cause weird problems in code you didn't write - or code you did... – B T Oct 25 '13 at 02:53
  • This works great! However, I needed to compare arrays of objects. I used `JSON.stringify(Object)` for the comparison. https://gist.github.com/harmstyler/7896595 – harmstyler Dec 10 '13 at 19:30
  • Nope, even this can be handled. For comparing objects, you need to use `for(var i in object)`. For `{a:1, b:2, c:666}` `i` will become `("a", "b", "c")` in that order. – Tomáš Zato Dec 10 '13 at 23:19
  • 2
    Wouldn't be a bad idea to make this code "strict mode" safe, by changing your first condition to `if (!this || !array)`. It would be a rare but possible case where you'd get a TypeError on `this.length` because the `this` value was set to `null` or `undefined`. – cookie monster Jan 01 '14 at 17:46
  • And would it still have a method `.compare`? – Tomáš Zato Jan 02 '14 at 09:04
  • 7
    I am surprised that there are no native functions to compare array, do I really need to copy paste your code for it to work? It seems something that should just be included in the language. – Charlie Parker Apr 06 '14 at 22:43
  • 1
    I think the problem is, that array comparing implementation may vary depending on what you need. If you just read the comments and other answers, you'll see that my code hardly covers everything that may be understood as array comparing. – Tomáš Zato Apr 08 '14 at 08:19
  • TomášZato good point but I still agree with Pinocchio. Event if it can be understood differently by different people, Evan's solution with the "strict" mode and renaming to .equals is a feature that would improve the overall quality of js scripts, since we can understand that many people don't see the for loops beyond the ones they write. Also, official documentation exists to solve the "many possible interpretations of what a .equals function should do" problem. – Johnride Apr 11 '14 at 18:13
  • To be honest, this function is damn too slow when you need to compare it quick (for example in mousemove event)... – Flash Thunder May 29 '14 at 04:16
  • 1
    Note that with this code, you wont be able to do `for (var i in myArray) { }` because `equals()` is now a property and the loop will now loop once on this property. – Olivier Pons Jun 02 '14 at 16:12
  • 2
    You should never loop through array like this. I remember that, in past when I was learning javascript, `i` would also contain `"length"` and other default properties. (in ancient IE) – Tomáš Zato Jun 02 '14 at 18:20
  • 135
    Changing a built-in type's prototype is definitely not **the right way** – Jasper Aug 14 '14 at 09:29
  • @Jasper `Array.equals` is not a built-in prototype according to [ECMAScript specs](http://www.ecma-international.org/ecma-262/5.1/#sec-15.4). Please check your sources again. – Tomáš Zato Aug 14 '14 at 11:59
  • 7
    @TomášZato Yes, but `Array` is. The point is, that since `Array` is a built-in, you shouldn't modify its prototype. – Jasper Aug 14 '14 at 12:38
  • 1
    @Jasper Why not? Anyway, you can easily rewrite my function to a procedural version, instead of the OOP one. – Tomáš Zato Aug 14 '14 at 13:46
  • 16
    @TomášZato basically, because in the future there might be a an `equals()` function on the `Array` prototype, and if it's different (e.g. deep vs shallow comparisons, or even just adding a parameter to allow selection of deep or shallow comparison) your code suddenly starts breaking other scripts that use this function... – Jasper Sep 01 '14 at 08:38
  • 43
    Besides, it's not about whether it's easy to rewrite, it's about the fact that an answer shouldn't recommend something that's considered bad practice (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Inheritance_and_the_prototype_chain#Bad_practice.3A_Extension_of_native_prototypes) and should **definitely** not do this below the header "The right way" – Jasper Sep 01 '14 at 09:07
  • 2
    I made a non-prototypal version of your array equals function here: http://stackoverflow.com/questions/27852356/finding-nested-duplicate-arrays-in-javascript-nested-array-uniq-in-lodash-unde/27859185#27859185 – Guilherme Rodrigues Jan 09 '15 at 12:12
  • 1
    @Jasper, @TomášZato: I recognised that extending prototype can be an issue, hence what I usually do is to enclosure that prototype with `if(typeof Array.prototype.equals != 'function') { ... }`... Not ideal, but certainly a workaround. – Robert Sim Apr 06 '15 at 11:25
  • 1
    @RobertSim And to be completelly correct, you could raise a warning in the console :) – Tomáš Zato Apr 06 '15 at 15:34
  • 2
    @TomášZato ah. i didn't think of that. I have been working on short term projects to consider the warnings. thanks. :) – Robert Sim Apr 07 '15 at 02:27
  • 5
    @RobertSim No. That doesn't work around the problem, it just shows that you have seen others who do that and copied them. Imagine the standard defining an equals for arrays which compares all members of the array using `===`. Now, code using your function will work incorrectly (because `Array.equals()` does something other than expected) in browsers that implement this new function. In browsers that do not have the new function, code using the new standard function, will appear to work, but not do what is expected. – Jasper Apr 07 '15 at 09:03
  • 2
    Combining code using your function and the new function has become impossible. Adding polyfills to the mix makes things worse: now it works one way if your code is executed first than when the polyfill is executed first. Even if no such function is added to the standard, all the same problems occur if someone else decides to do the same as you, but has a different opinion on what equals should do... And showing an Exception does not solve any problems. It would be a good option if you had to do this, but as you said yourself, you don't have to; you can easily convert this to a normal function. – Jasper Apr 07 '15 at 09:09
  • 7
    No, you should only add a function to the prototype if you *know* *exactly* what the function should do. This is basically only the case for polyfills... – Jasper Apr 07 '15 at 09:11
  • @Jasper, RobertSim, Tomáš Zato: Jasper is obviously right, I don't even perceive a debate -- as soon as we introduce multiple independent codebases in the same environment (a single third-party library will do) then all arguments for modifying a shared prototype become moot. It used to be that we couldn't [subclass arrays](http://perfectionkills.com/how-ecmascript-5-still-does-not-allow-to-subclass-an-array/), but as of January 2015 it seems that [ES6 semantics](http://www.2ality.com/2015/02/es6-classes-final.html) allow for a clean way to do this. – tne May 06 '15 at 11:11
  • 1
    @tne There's no right or wrong in fact. There's a group of people that think they have some patent on the bug wisdom how programs should be written. It's a lie. It only shows how close minded some can be and how flexibility is unknown word for some. Clearly, in big, long-term applications and frameworks, one should think twice before defining any single function name and definitelly defining custom prototype functions for built-in types could turn out to be a bad idea after 5 years. But not everybody is making a program that should last 5 years. You can enjoy your clumsy... – Tomáš Zato May 06 '15 at 11:22
  • 1
    @tne ... overkill designs. But do others the courtesy of letting them enjoy the comfort of swift and clean code with as few type strokes as possible. Some of us just like getters, setters, operator overloading and writing own built in prototypes because we're creative and we like to change the language we're using. And in 5 years, whatever we've been writing will be long forgotten and won't matter. – Tomáš Zato May 06 '15 at 11:25
  • 2
    @TomášZato I definitely accept all your arguments whenever you have a single codebase, especially if it's short-lived as you say. If you (1) include *any* third-party library (which is extremely common nowadays) and (2) the code has a small chance to still be in use for ES7+, then you accept that your application might suddenly start crashing (or worse, display silent but incorrect behavior that *you might never know about*) as soon as users upgrade their runtimes (browsers, server-side envs,...). I admit I'm a bit irritated that you consider subclassing "overkill", it's exactly what you want. – tne May 06 '15 at 11:40
  • 2
    @tne Subclassed array can be only used with `new ImprovedArray()` whereas my solution works on anything instantiated as `[]` no matter whether it comes from external source, parsed JSON or your program. My answer has been here for 2 years and is still valid and doesn't break anything (only irritates some people which I don't care about). Observational evidence is the only thing superior to logical arguments (and what you say is logical and true). Meanwhile anybody who cares about the code he writes will read your comments and make his decision with your advice on mind. – Tomáš Zato May 06 '15 at 11:56
  • @TomášZato Why yes, that's the whole point; to avoid polluting the global prototype. I must stress that's it's absolutely trivial to wrap any array in such a subtype; so the difference is between "opt-in" vs "mandatory" custom behavior for third-parties. In a weird way I respect your nonchalant attitude toward what you might perceive as cargo-culting, but unfortunately it's these kinds of practices that force spec writers to weird corners just to avoid "breaking" software that was in fact already broken. Many languages have standard default equals functionality, it's not inconceivable for JS. – tne May 06 '15 at 12:28
  • 9
    @TomášZato I agree with you that you can do whatever you want in your own code. You may not run into any of the problems, but if you do, you only shot yourself in the foot. However, we're talking about a recommendation on a public website, and one which calls itself "The right way" at that. The same reasoning does not go, and you shouldn't shoot other people in the foot. – Jasper May 06 '15 at 13:36
  • 1
    @Jasper If you wanna go all analogic on me, please keep on mind that my post is merely a recommendation how to shoot yourself in the leg. I still do not think the whole problem is as terrible as you picture it. As I mentioned, for 2 years nothing changed. I doubt another 2 will bring anything new. If they do, I am here to update the question - not a second before. Long investments that don't pay off kill the fun in programming. – Tomáš Zato May 06 '15 at 13:43
  • 6
    @TomášZato Recommendations on how to shoot yourself in the leg don't belong on this site (unless the question is "how do I shoot myself in the leg"). And your "I'll update the answer" shows you still don't understand the problems. Because at that point, anyone who used this code, isn't here to see your update and yet is feeling the pain in his foot. And how about two people following this strategy? Their code can't be used on the same site. Your answer might work (in some circumstances), but that doesn't make it any less wrong... – Jasper May 06 '15 at 13:56
  • 3
    Your `Array.ptototype.equals` should use a strict comparaison. Else things like `[[]].equals([false]);` will return true. – dievardump Sep 29 '15 at 15:20
  • @dievardump Strict comparison in non-typed languages has also it's pitfalls (`1` vs `"1"`). Anyway I don't think `[[]].equals([false]);` would return true by just looking on the code. Have you tested that? – Tomáš Zato Sep 29 '15 at 15:30
  • Yes here : http://jsfiddle.net/ku9uw18k/ -- since `[] != false` === false your code never return false. Would be the same with `[""].equals([false]);` and for me `[1].equals(["1"])` should return false – dievardump Sep 29 '15 at 15:58
  • @dievardump Thanks, good to know that. Anyway I was considering strict comparison and I concluded, as I was already pointing out, that most people will desire `"1"` and `1` to be equal. Those like you, who are aware of the typing in javascript, will be skilled enough to edit the code to their needs. My code is just a template for you. – Tomáš Zato Sep 29 '15 at 16:06
  • 2
    This is apparently a pretty hot topic.. I found myself disappointed with how js builtins didn't handle nested arrays correctly. So using @TomášZato 's code, I've created a `contains` and `indexOf` function, which much like Zato's `equals` function, properly handle nested arrays. All the functions are added to the Array prototype. The code is available here: https://jsfiddle.net/SamyBencherif/8352y6yw/ – Samie Bencherif Mar 07 '16 at 02:07
  • true.equals(false) equates to true, and false.equals(true) also equates to true using this method, pretty funny for the giggles but I imagine when comparing object.equals(false) you'd get unexpected results. – Bill Effin Murray Dec 20 '16 at 23:15
  • Seems like great. But if arrays have same values in different orders, it returns false. This should be corrected, cause this is very important. – Otvazhnii Apr 19 '17 at 09:40
  • @MrEvgenyShcherbina This is intended. You have to sort the arrays if you want to compare them regardless of order of values. – Tomáš Zato Apr 19 '17 at 10:57
  • 1
    How could such a simple task warrant so many lines of code?? I feel like I need to deploy a microservice to use this solution. – rigdonmr Aug 10 '17 at 20:34
  • @rigdonmr apparently you'll need your own language too as the Array prototype is being modified – Emobe Mar 13 '19 at 10:49
  • can someone help me it works fine for one array of objects in my script but the other one which i tested is also an object return "Uncaught TypeError: controlled.equals is not a function" – Woold May 11 '20 at 14:29
  • why does my arra have equals: true added like {... , equals: true} i don't want that – Woold May 11 '20 at 14:44
620

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

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

Same as above but 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 in 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 return true

dippas
  • 58,591
  • 15
  • 114
  • 126
user2782196
  • 6,295
  • 1
  • 12
  • 3
  • 25
    I like this, although readers should be aware this only works on sorted arrays. – Ellen Spertus Dec 15 '13 at 15:05
  • 23
    It works on any kind of arrays, sorted or not @espertus – Michał Miszczyszyn Mar 24 '16 at 14:03
  • 1
    @MichałMiszczyszyn Are you sure? I am not a JS expert, but it looks to me as though the function is only true if the i-th element of a1 is equal to the i-th element of a2. – Ellen Spertus Mar 25 '16 at 20:13
  • 51
    Yes, exactly. This function is supposed to compare two arrays, it doesn't matter if they're sorted or not, their consecutive elements have to be equal. – Michał Miszczyszyn Mar 26 '16 at 00:39
  • 32
    @espertus Indeed, it won't return true if the elements do not have the exact same order in both arrays. However, the goal of an equality check is not to check if they contains the same elements but to check if they have the same element in the same orders. – Quentin Roy Jun 06 '16 at 03:25
  • 12
    If you want to check if both arrays are equals, containing the same unsorted items (but not used multiple times), you can use `a1.length==a2.length && a1.every((v,i)=>a2.includes(v))`: `var a1 =[1,2,3], a2 = [3,2,1];` (`var a1 =[1,3,3], a2 = [1,1,3];` will not work as expected) – mems Nov 21 '16 at 15:25
  • 2
    This is a great answer, although it comes with a caveat. The answerer even highlights the caveat: **this works only for scalar arrays** but I think many people may overlook that detail due to word `scalar` being used, something I assume most of don't hear often. Might do this question justice by touching up on that piece and further clarifying the example... – Govind Rai Jan 07 '17 at 00:36
  • 3
    You should not sort the second array for every element of the first one. Sort them both in the beginning of the function execution. Or, even better, add a function parameter to determine if sorting is required. Also, there is no meaning in organizing all code into a single line, it's hard to read. – Slava Fomin II Nov 14 '18 at 10:55
  • 4
    Also, calling the `sort()` method will mutate the original array, which is almost never a good thing. You should clone it beforehand. – Slava Fomin II Nov 14 '18 at 10:59
  • 3
    It's not good practice to use sort inside loop. Just sort the arrays once before the comparison instead of doing it at every single iteration. – Petroff Jan 23 '19 at 10:41
  • @mems You might as well update the answer, your code is even faster: http://jsben.ch/iqfgt – Fabian von Ellerts Feb 14 '19 at 09:56
  • 2
    Or if order doesn't matter, `array1.length === array2.length && array1.every(value=> array2.includes(value))` – Nic Scozzaro May 10 '20 at 00:34
  • The variant with .sort() was sorting array2 on each iteration AND mutating the arrays! I couldn't look at it. – Pawel Sep 16 '20 at 21:00
  • If you're going to sort first check if `array1.length === array2.length` to avoid unneeded sorting of array2 – Phani Rithvij Dec 07 '20 at 11:43
  • @EllenSpertus, you're thinking of sets with duplicates allowed. – Phani Rithvij Dec 07 '20 at 11:47
  • I wasn't able to get this to return false. Added 'banana' to one array and not the other, expecting the two to mismatch. What am I missing? – Kreidol Oct 13 '22 at 18:14
291

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
Beau Smith
  • 33,433
  • 13
  • 94
  • 101
Jason Boerner
  • 3,338
  • 1
  • 13
  • 4
234

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.

radtek
  • 34,210
  • 11
  • 144
  • 111
  • good answer but why []==[] return false ? both are simple objects then why ? – Pardeep Jain Jan 17 '16 at 19:03
  • 5
    @PardeepJain, this is because by default, the equality operator in ECMAScript for Objects returns true when they reference the same memory location. Try var x = y = []; // now equality returns true. – radtek Jan 17 '16 at 19:52
  • 13
    just to note that JSON stringify function is not quick. Used with larger arrays will definitely introduce lag. – Lukas Liesis Apr 29 '17 at 11:03
  • 21
    The question specifically asks whether there is a *better/faster* way than using JSON.stringify. – Don Hatch May 10 '17 at 01:02
  • 2
    It gets into more detail on why this may be a good solution for some situations. – radtek May 11 '17 at 21:30
  • And this explains `JSON.stringify()` and how it can be the best choice depending on what you are trying to do. I shared what I found and it looks like its helping others decide. – radtek Sep 08 '17 at 18:23
  • This will crash when there is circular reference. – hqzxzwb Jan 11 '19 at 15:21
  • 2
    Honestly, I did not notice at first that original question mentions `JSON.stringify()` - for simple use cases it feels the easiest one... – Mars Robertson Mar 02 '19 at 13:52
  • For arrays with only primitive types inside it, `[1,2,3] == [1,2,3] +"" ` also works. – Mohi Nov 14 '21 at 21:38
  • @DonHatch Yeah but, to be fair, when I searched for "how to compare arrays" I only read the question title, then went straight to the answers. Maybe it's just me but it was helpful to have it repeated down here 'cause I blew through the question text and didn't remember this was a solution until I saw this answer. ‍♂️ – Jason C May 26 '22 at 13:42
174

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.

3rd party edit

It seems to me that jsbench is now sorting from fast (100%) to slower (for example 11%). The code sample contains arrEvery() and a slowed down version.


function arrEvery(a1,a2) 
{
    // user2782196: http://stackoverflow.com/a/19746771/308645
    return a1.every((v,i)=> v === a2[i]);
}

// slowed down
function arrEveryWithSlowDown(a1,a2) 
{
    setTimeout(() => {
        console.log("Slow down pal!");
    }, 1500);
    return a1.every((v,i)=> v === a2[i]);
}

The slowed down version of arrEvery has less percentage. The number in brackets might be the number of cycels / operations run.

jsbench.ch result array comparison

surfmuggle
  • 5,527
  • 7
  • 48
  • 77
unitario
  • 6,295
  • 4
  • 30
  • 43
  • If you bump the array size, these numbers don't apply (especially the reduce approach). Try with `Array.from({length: 1000}).map((a,v)=> `${v}`.padStart(10,2));` – Narayon Aug 27 '19 at 10:49
  • Should use `sort()` before `a1` & `a2` join. e.g. `a1.sort().join("")===a2.sort().join("")` – KR Tirtho Nov 19 '20 at 17:23
  • 5
    `join('')` is dangerous as `['foo', 'bar'].join('') == ['foobar'].join('')`. I prefer `a1 ==''+ a2`. – Cees Timmerman Nov 27 '21 at 20:57
  • 16
    what do these % numbers even mean? – Human programmer Apr 05 '22 at 19:15
  • @KRTirtho If you use sort, `[1, 2]` will equal `[2, 1]`, which is wrong in most cases. If you specifically want a unordered comparison, fine, you can sort, but that is not the normal case and not the question. – rjmunro Nov 30 '22 at 17:50
  • 3
    @TheHumanCat I'm pretty sure the slowest implementation represents 100% while other represent a fraction of that time. So using `while` would take 67% of the time it takes using `stringify`. This is somewhat similar to baker's percentages… – Shawn Dec 17 '22 at 17:54
  • @Shawn, @TheHumandCat i believe that less percentages means fewer operations and therefore slower. I [forked the sample](http://jsben.ch/3KUMH) and added a setTimeout to `arrEveryWithSlowDown (412,985)` the result was 10,75% compared to 98.31% for `arrEvery (4,001,413)` – surfmuggle Apr 13 '23 at 19:42
  • Your `arrEvery` does not work for different sized arrays. – Beyondo Aug 14 '23 at 05:14
  • @Beyondo No, it assumes single-dimensional arrays of equal length to ensure common benchmark between the different solutions. Please review note. – unitario Aug 14 '23 at 09:25
  • @unitario Oh, my bad – Beyondo Aug 14 '23 at 09:49
89

The Practical Way

I think it's wrong to say a particular implementation is "The Right Way™" if it's only "right" ("correct") in contrast to a "wrong" solution. Tomáš's solution is a clear improvement over string-based array comparison, but that doesn't mean it's objectively "right". What is right anyway? Is it the fastest? Is it the most flexible? Is it the easiest to comprehend? Is it the quickest to debug? Does it use the least operations? Does it have any side effects? No one solution can have the best of all the things.

Tomáš's could say his solution is fast but I would also say it is needlessly complicated. It tries to be an all-in-one solution that works for all arrays, nested or not. In fact, it even accepts more than just arrays as an input and still attempts to give a "valid" answer.


Generics offer reusability

My answer will approach the problem differently. I'll start with a generic arrayCompare procedure that is only concerned with stepping through the arrays. From there, we'll build our other basic comparison functions like arrayEqual and arrayDeepEqual, etc

// arrayCompare :: (a -> a -> Bool) -> [a] -> [a] -> Bool
const arrayCompare = f => ([x,...xs]) => ([y,...ys]) =>
  x === undefined && y === undefined
    ? true
    : Boolean (f (x) (y)) && arrayCompare (f) (xs) (ys)

In my opinion, the best kind of code doesn't even need comments, and this is no exception. There's so little happening here that you can understand the behaviour of this procedure with almost no effort at all. Sure, some of the ES6 syntax might seem foreign to you now, but that's only because ES6 is relatively new.

As the type suggests, arrayCompare takes comparison function, f, and two input arrays, xs and ys. For the most part, all we do is call f (x) (y) for each element in the input arrays. We return an early false if the user-defined f returns false – thanks to &&'s short-circuit evaluation. So yes, this means the comparator can stop iteration early and prevent looping through the rest of the input array when unnecessary.


Strict comparison

Next, using our arrayCompare function, we can easily create other functions we might need. We'll start with the elementary arrayEqual

// equal :: a -> a -> Bool
const equal = x => y =>
  x === y // notice: triple equal

// arrayEqual :: [a] -> [a] -> Bool
const arrayEqual =
  arrayCompare (equal)

const xs = [1,2,3]
const ys = [1,2,3]
console.log (arrayEqual (xs) (ys))      //=> true
// (1 === 1) && (2 === 2) && (3 === 3)  //=> true

const zs = ['1','2','3']
console.log (arrayEqual (xs) (zs))      //=> false
// (1 === '1')                          //=> false

Simple as that. arrayEqual can be defined with arrayCompare and a comparator function that compares a to b using === (for strict equality).

Notice that we also define equal as it's own function. This highlights the role of arrayCompare as a higher-order function to utilize our first order comparator in the context of another data type (Array).


Loose comparison

We could just as easily defined arrayLooseEqual using a == instead. Now when comparing 1 (Number) to '1' (String), the result will be true

// looseEqual :: a -> a -> Bool
const looseEqual = x => y =>
  x == y // notice: double equal

// arrayLooseEqual :: [a] -> [a] -> Bool
const arrayLooseEqual =
  arrayCompare (looseEqual)

const xs = [1,2,3]
const ys = ['1','2','3']
console.log (arrayLooseEqual (xs) (ys))    //=> true
// (1 == '1') && (2 == '2') && (3 == '3')  //=> true

Deep comparison (recursive)

You've probably noticed that this is only shallow comparison tho. Surely Tomáš's solution is "The Right Way™" because it does implicit deep comparison, right ?

Well our arrayCompare procedure is versatile enough to use in a way that makes a deep equality test a breeze …

// isArray :: a -> Bool
const isArray =
  Array.isArray

// arrayDeepCompare :: (a -> a -> Bool) -> [a] -> [a] -> Bool
const arrayDeepCompare = f =>
  arrayCompare (a => b =>
    isArray (a) && isArray (b)
      ? arrayDeepCompare (f) (a) (b)
      : f (a) (b))

const xs = [1,[2,[3]]]
const ys = [1,[2,['3']]]
console.log (arrayDeepCompare (equal) (xs) (ys)) //=> false
// (1 === 1) && (2 === 2) && (3 === '3')         //=> false

console.log (arrayDeepCompare (looseEqual) (xs) (ys)) //=> true
// (1 == 1) && (2 == 2) && (3 == '3')                 //=> true

Simple as that. We build a deep comparator using another higher-order function. This time we're wrapping arrayCompare using a custom comparator that will check if a and b are arrays. If so, reapply arrayDeepCompare otherwise compare a and b to the user-specified comparator (f). This allows us to keep the deep comparison behavior separate from how we actually compare the individual elements. Ie, like the example above shows, we can deep compare using equal, looseEqual, or any other comparator we make.

Because arrayDeepCompare is curried, we can partially apply it like we did in the previous examples too

// arrayDeepEqual :: [a] -> [a] -> Bool
const arrayDeepEqual =
  arrayDeepCompare (equal)

// arrayDeepLooseEqual :: [a] -> [a] -> Bool
const arrayDeepLooseEqual =
  arrayDeepCompare (looseEqual)

To me, this already a clear improvement over Tomáš's solution because I can explicitly choose a shallow or deep comparison for my arrays, as needed.


Object comparison (example)

Now what if you have an array of objects or something ? Maybe you want to consider those arrays as "equal" if each object has the same id value …

// idEqual :: {id: Number} -> {id: Number} -> Bool
const idEqual = x => y =>
  x.id !== undefined && x.id === y.id

// arrayIdEqual :: [a] -> [a] -> Bool
const arrayIdEqual =
  arrayCompare (idEqual)

const xs = [{id:1}, {id:2}]
const ys = [{id:1}, {id:2}]
console.log (arrayIdEqual (xs) (ys)) //=> true
// (1 === 1) && (2 === 2)            //=> true

const zs = [{id:1}, {id:6}]
console.log (arrayIdEqual (xs) (zs)) //=> false
// (1 === 1) && (2 === 6)            //=> false

Simple as that. Here I've used vanilla JS objects, but this type of comparator could work for any object type; even your custom objects. Tomáš's solution would need to be completely reworked to support this kind of equality test

Deep array with objects? Not a problem. We built highly versatile, generic functions, so they'll work in a wide variety of use cases.

const xs = [{id:1}, [{id:2}]]
const ys = [{id:1}, [{id:2}]]
console.log (arrayCompare (idEqual) (xs) (ys))     //=> false
console.log (arrayDeepCompare (idEqual) (xs) (ys)) //=> true

Arbitrary comparison (example)

Or what if you wanted to do some other kind of kind of completely arbitrary comparison ? Maybe I want to know if each x is greater than each y

// gt :: Number -> Number -> Bool
const gt = x => y =>
  x > y

// arrayGt :: [a] -> [a] -> Bool
const arrayGt = arrayCompare (gt)

const xs = [5,10,20]
const ys = [2,4,8]
console.log (arrayGt (xs) (ys))     //=> true
// (5 > 2) && (10 > 4) && (20 > 8)  //=> true

const zs = [6,12,24]
console.log (arrayGt (xs) (zs))     //=> false
// (5 > 6)                          //=> false

Less is More

You can see we're actually doing more with less code. There's nothing complicated about arrayCompare itself and each of the custom comparators we've made have a very simple implementation.

With ease, we can define exactly how we wish for two arrays to be compared — shallow, deep, strict, loose, some object property, or some arbitrary computation, or any combination of these — all using one procedure, arrayCompare. Maybe even dream up a RegExp comparator ! I know how kids love those regexps …

Is it the fastest? Nope. But it probably doesn't need to be either. If speed is the only metric used to measure the quality of our code, a lot of really great code would get thrown away — That's why I'm calling this approach The Practical Way. Or maybe to be more fair, A Practical Way. This description is suitable for this answer because I'm not saying this answer is only practical in comparison to some other answer; it is objectively true. We've attained a high degree of practicality with very little code that's very easy to reason about. No other code can say we haven't earned this description.

Does that make it the "right" solution for you ? That's up for you to decide. And no one else can do that for you; only you know what your needs are. In almost all cases, I value straightforward, practical, and versatile code over clever and fast kind. What you value might differ, so pick what works for you.


Edit

My old answer was more focused on decomposing arrayEqual into tiny procedures. It's an interesting exercise, but not really the best (most practical) way to approach this problem. If you're interested, you can see this revision history.

Mulan
  • 129,518
  • 31
  • 228
  • 259
  • +1 for _"the best kind of code doesn't even need comments"_ and your beautiful answer of course. However, I wonder why you decided against `Array.prorotype.every`. It takes a predicate and the iteration can be stopped early. It is also easy to read provided you know that the passed function has an optional 2nd argument: `f => xs => ys => xs.length === ys.length ? xs.every((y, x) => f(x) (ys[y])) : false`. I guess the implementation is more memory efficient. It is debatable if this is an idiomatic usage of `every` though. `ys[y]` exposes algorithmic details and is less declarative... –  Aug 15 '16 at 18:46
  • @LUH3417 yep, I could've used `.every` as you described you have you to flip the `x` and `y` parameters – `xs.every((x,i) => f (x) (ys[i]))`. I think it's a useful and idiomatic application of `.every` but I did want to show how to build a generic higher-order procedure from scratch. Also, I know `.length` and accessing an array element by index (`ys[i]`) is not very costly in JavaScript, but I wanted to show that it could be done without either of those too. – Mulan Aug 15 '16 at 19:21
  • And yes, I know destructuring the array technical does `xs[0]`, `xs.slice(1)` but I think it's a safer (and less verbose) pattern than writing your own direct accessors. Thanks for the comment ^_^ – Mulan Aug 15 '16 at 19:24
  • 14
    "the best kind of code doesn't even need comments" ... hate to say it, but this code could use more of a comment, and/or a different name-- "compare" is pretty vague. If I'm reading correctly, your "compare" is essentially a curried recursive "every". I think. Or is it a curried recursive "some"? Hmm. This is requiring more thinking than necessary. Perhaps a better name would be "arraysEquivalent", leveraging the standard terminology of "equivalence relation". Or, even clearer (to me anyway), "recursivelyEquivalent". – Don Hatch May 10 '17 at 01:09
  • 1
    @DonHatch thanks for the opportunity to reply. By "compare" do you mean `arrayCompare`? Yes the function is curried, but it differs from `some` and `every`. `arrayCompare` takes a comparator and *two* arrays to compare. I chose a specifically generic name because we can compare arrays using any arbitrary function. The function is curried so it can be specialised to create new array comparison functions (eg, `arrayEqual`). Can you suggest a better name? What areas do you feel need additional comments or explanation? I'm happy to discuss ^_^ – Mulan May 10 '17 at 01:14
  • Right, I meant the "compare" in your `arrayCompare`. "compare" is unfortunately vague since it is used in lots of differerent ways in other contexts: e.g. the C language's qsort function takes a "compar" functor that returns -1,0, or 1 depending on whether the first arg is less than, equal to, or greater than the second; c++'s std::sort takes a "comp" functor that returns true iff the first arg is less than the second, etc. I think if you used some variant of the word "equivalent" instead, it would make it more immediately clear that the intent is to return a bool expressing equivalence. – Don Hatch May 10 '17 at 01:19
  • 1
    Not sure if my point is clear yet-- but my point is, your function isn't really intended to take an *arbitrary* function, I don't think-- it's intended to take an [equivalence relation](https://en.wikipedia.org/wiki/Equivalence_relation), and it returns an equivalence relation. That's important-- it wouldn't do anything sensible (I don't think) if given some other kind of arbitrary binary function like the ones I mentioned, even ones that people often call "compare". So I think it would be helpful to put "equivalent" in the name in place of "compare". – Don Hatch May 10 '17 at 01:29
  • Don I understand your point more clearly now. Though I think this is maybe just a JavaScipt naming convention. `===`, `==`, `!=`, `>`, `<`, etc are called [comparison operators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators?v=test) in JavaScript. I understand "comparison" used in a different context (eg sorting) can have a different meaning than the way I'm using "compare" here - though I think both are valid – Mulan May 10 '17 at 01:50
  • Looking at `arrayGt` in my answer, I think deriving from (eg) `arrayEquivalence` would feel wrong because `gt` (`>`) is not testing for *equivalence* - hmm. I still wonder if there's a better name altogether. – Mulan May 10 '17 at 01:59
  • Oh! I see, gt *does* make sense. I missed that at first, even though you included it in your answer, because I didn't read your answer fully, sorry about that. Maybe something like "recursiveEveryBinary" or "recursiveEvery2". Thanks. – Don Hatch May 10 '17 at 02:35
  • 1
    @ftor, author: super helpful answer, nice work, +1. Feedback: You advocate simplicity, yet no way is an expression with three arrows on one line simple or easy to understand for many developers. For ex: f=> ([x,...xs]) => ([y,...ys]) =>. I constantly use this and still had to mentally decompose it, rather than "just look at it". Second point ftor is right, use every. Even weighing your reasons, on balance it seems better not only to me, but also from your perspective when attempt to infer your design philosophy. – whitneyland Nov 22 '17 at 20:18
  • @Lee this [curried style](https://stackoverflow.com/questions/32782922/what-do-multiple-arrow-functions-mean-in-javascript/32787782#32787782) is easier to understand with time, but it is *just style* – This question is specifically about array comparison and not really the place for me to say *to curry* or *not to curry*. Writing the function in uncurried form `arrayCompare (f, [x,...xs], [y,...xs]) => ...` may improve readability for some, but it's just a *style* difference – the two variants are equivalent when concerning any meaningful factors. Thanks for the comment ^_^ – Mulan Nov 22 '17 at 20:37
  • @Lee, the style in which I write functional programs in JavaScript has changed dramatically over time. This answer was a little stale, so I updated with styles I've been using more recently – Mulan Nov 22 '17 at 20:56
  • I don’t see how currying is just style. It became a thing in math for reasons practical, not aesthetic, it was easier to deal with certain constructs that way, likewise for computer science. continuing comment please wait... – whitneyland Nov 22 '17 at 23:19
  • Please don't get hung up on the word *style* – I'm only concerned with providing an answer that utilizes pure (ie referentially transparent) functions – this can be done using currying, or without. Advantages of one style/technique/theory/rule/pattern over another are not the talking point of this answer. I chose curried style because `arrayCompare` specializes naturally by accepting a higher order function, but also just because I like curried style ^_^ – Mulan Nov 22 '17 at 23:26
  • ...Therefore the objection is, only in cases like these, currying has been reduced to a matter style, possibly being even more difficult for the average programmer. This is conjecture but I feel confident a large majority of devs would say a multiple parameter arrow declaration carries a lower conflictive load in their minds compared to the curried example. It goes beyond the 3 arrows per line, () () feels unusual in javascript, not idiomatic. If the conjecture is correct, it adds a small penalty to the learning curve as new people continually rotate into a code base, style only is ok? – whitneyland Nov 22 '17 at 23:31
  • 2
    I understand this is a place for learning, but I make an assumption here that the average programmer studying functional style can transform any curried function to an uncurried one. My answer does not make the suggestion that this *style* is meant to be used in your own program – write it uncurried, write it using your own indentation rules, write it however you want – I write my answers in a style that I believe expresses the program best. I also like to invite others to challenge the way we express our programs syntactically – Mulan Nov 22 '17 at 23:36
  • To be clear I don’t care about style only the advantages of different techniques. I see no concrete benefits here and possible negatives, that’s it. To be truly fair with you i’d have to try it for a while. The teams you work with are a huge factor. I’ve worked on very advanced teams at pure tech companies, but also consulted for corporate america. The difficulty of introducing new things varies widely based on the team in my experience. – whitneyland Nov 22 '17 at 23:37
  • To be clear, in this context I consider *style* and *technique* to be the same – I don't care about either; I'm only trying to demonstrate a practical, functional approach to the question using a style that I deemed appropriate – Mulan Nov 22 '17 at 23:42
  • 1
    Lee, we're really missing each other here – I'm not trying to convince you to write curried functions, or *not* to write them either. My answer is expressed in curried style and uses rather unconventional whitespace, but if that doesn't work for your team, feel free to change the style(s) to whatever you want – I mean, I really don't see a problem unless you're copy/pasting code from SO directly into your program. The answer just shows *how* the moving parts work – tweak implementation and style to your fancy. I think that applies to all answers on SO, doesn't it? – Mulan Nov 22 '17 at 23:48
  • I hope I’m not communicating negativity or irratitation because that’s not my felling at all. Rather, as we are all here sharing and learning, the intent is just to get the most out of it. If I think I notice a better way of doing something in my mind it’s a guaranteed win, because whether I turn out to be right or wrong, somebody has further learned, improved, sharpened thinking. The matter of ulrmately being right or wrong is not itself a big motivation for me in learning or teaching contexts. – whitneyland Nov 23 '17 at 00:05
  • Lee, I don't sense any negativity or irritation. I think the opening sentence of my answer agrees with latter part of your comment. Thanks for the discussion ^_^ – Mulan Nov 23 '17 at 03:47
  • @Lee Currying is an abstraction, namely over arity. The question is thus does abstraction simplify the code? I'd say usually not. Abstraction increases the reader's necessary level of experience to comprehend code, because it hides details. Higher order functions on the other hand offer a wider range of applications than their first order counterparts. They are generalizations. Now with currying you can use specialized instances of a generic function by assigning intermediate functions to variables. So currying may complicate code, but it also includes some nice properties. –  Nov 23 '17 at 12:40
  • Ok cool, I think we are exactly in sync on this discussion point and trade offs. When you say abstraction increases need for experience/comprehension, I assume you mean w.r.t. this subject, and I would agree. It seems a ironic that generally speaking, abstraction often can do the opposite, make things easier to grok and build on. Too bad you don’t live next to the same bar, this stuff could extend to all kinds of interesting tangents over a few beers. :-) – whitneyland Nov 23 '17 at 14:57
  • Really great approach and I agree the reusability is great (even if out of scope of the question). The complexity is high even in 2018 when ES6 syntax and functional approach is well understood. The hardest part to grok is that it uses destructing and recursion for array iteration. Thus you have the side-effect `x === undefined && y === undefined` which requires you to read backwards to get then it is required to ensure both array iterations yield `undefined` which means they are of equal length. A length check hidden in the pattern used does require comments. – bucabay Oct 06 '18 at 09:15
  • @user633183, great answer, but the fact that a large percentage of your comments here are to defend your choice of "style" actually works against the very thing you're trying to defend.I think your choice of "style" is preposterous from the point of view of SO's purpose. It's a little like "Do you have the time?" "Let me show you how to build a clock" – G. Stoynev Aug 06 '19 at 11:33
67

It's unclear what you mean by "identical". For example, are the arrays a and b below identical (note the nested arrays)?

var a = ["foo", ["bar"]], b = ["foo", ["bar"]];

Here's an optimized array comparison function that compares corresponding elements of each array in turn using strict equality and does not do recursive comparison of array elements that are themselves arrays, meaning that for the above example, arraysIdentical(a, b) would return false. It works in the general case, which JSON- and join()-based solutions will not:

function arraysIdentical(a, b) {
    var i = a.length;
    if (i != b.length) return false;
    while (i--) {
        if (a[i] !== b[i]) return false;
    }
    return true;
};
Tim Down
  • 318,141
  • 75
  • 454
  • 536
  • @ASDF: It's unclear from the question what "identical" means. Obviously this answer just does a shallow check. I'll add a note. – Tim Down Sep 04 '14 at 13:33
  • this fails for arraysIdentical([1, 2, [3, 2]],[1, 2, [3, 2]]); – Gopinath Shiva Jul 31 '15 at 13:08
  • 4
    @GopinathShiva: Well, it only fails if you're expecting it to return `true`. The answer explains that it won't. If you need to compare nested arrays, you could easily add a recursive check. – Tim Down Jul 31 '15 at 23:16
30

Building off Tomáš Zato's answer, I agree that just iterating through the arrays is the fastest. Additionally (like others have already stated), the function should be called equals/equal, not compare. In light of this, I modified the function to handle comparing arrays for similarity - i.e. they have the same elements, but out of order - for personal use, and thought I'd throw it on here for everyone to see.

Array.prototype.equals = function (array, strict) {
    if (!array)
        return false;

    if (arguments.length == 1)
        strict = true;

    if (this.length != array.length)
        return false;

    for (var i = 0; i < this.length; i++) {
        if (this[i] instanceof Array && array[i] instanceof Array) {
            if (!this[i].equals(array[i], strict))
                return false;
        }
        else if (strict && this[i] != array[i]) {
            return false;
        }
        else if (!strict) {
            return this.sort().equals(array.sort(), true);
        }
    }
    return true;
}

This function takes an additional parameter of strict that defaults to true. This strict parameter defines if the arrays need to be wholly equal in both contents and the order of those contents, or simply just contain the same contents.

Example:

var arr1 = [1, 2, 3, 4];
var arr2 = [2, 1, 4, 3];  // Loosely equal to 1
var arr3 = [2, 2, 3, 4];  // Not equal to 1
var arr4 = [1, 2, 3, 4];  // Strictly equal to 1

arr1.equals(arr2);         // false
arr1.equals(arr2, false);  // true
arr1.equals(arr3);         // false
arr1.equals(arr3, false);  // false
arr1.equals(arr4);         // true
arr1.equals(arr4, false);  // true

I've also written up a quick jsfiddle with the function and this example:
http://jsfiddle.net/Roundaround/DLkxX/

17

On the same lines as JSON.encode is to use join().

function checkArrays( arrA, arrB ){

    //check if lengths are different
    if(arrA.length !== arrB.length) return false;


    //slice so we do not effect the original
    //sort makes sure they are in order
    //join makes it a string so we can do a string compare
    var cA = arrA.slice().sort().join(","); 
    var cB = arrB.slice().sort().join(",");

    return cA===cB;

}

var a = [1,2,3,4,5];
var b = [5,4,3,2,1];
var c = [1,2,3,4];
var d = [1,2,3,4,6];
var e = ["1","2","3","4","5"];  //will return true

console.log( checkArrays(a,b) );  //true
console.log( checkArrays(a,c) );  //false
console.log( checkArrays(a,d) );  //false
console.log( checkArrays(a,e) );  //true

Only problem is if you care about types which the last comparison tests. If you care about types, you will have to loop.

function checkArrays( arrA, arrB ){

    //check if lengths are different
    if(arrA.length !== arrB.length) return false;

    //slice so we do not effect the orginal
    //sort makes sure they are in order
    var cA = arrA.slice().sort(); 
    var cB = arrB.slice().sort();

    for(var i=0;i<cA.length;i++){
         if(cA[i]!==cB[i]) return false;
    }

    return true;

}

var a = [1,2,3,4,5];
var b = [5,4,3,2,1];
var c = [1,2,3,4];
var d = [1,2,3,4,6];
var e = ["1","2","3","4","5"];

console.log( checkArrays(a,b) );  //true
console.log( checkArrays(a,c) );  //false
console.log( checkArrays(a,d) );  //false
console.log( checkArrays(a,e) );  //false

If the order should remain the same, than it is just a loop, no sort is needed.

function checkArrays( arrA, arrB ){

    //check if lengths are different
    if(arrA.length !== arrB.length) return false;


    for(var i=0;i<arrA.length;i++){
         if(arrA[i]!==arrB[i]) return false;
    }

    return true;

}

var a = [1,2,3,4,5];
var b = [5,4,3,2,1];
var c = [1,2,3,4];
var d = [1,2,3,4,6];
var e = ["1","2","3","4","5"];

console.log( checkArrays(a,a) );  //true
console.log( checkArrays(a,b) );  //false
console.log( checkArrays(a,c) );  //false
console.log( checkArrays(a,d) );  //false
console.log( checkArrays(a,e) );  //false
epascarello
  • 204,599
  • 20
  • 195
  • 236
  • Thanks, @epascarello, in my specific case, I am only comparing the order of elements, not types, so `.join();` would work as well. Thanks for the insight. – Julian H. Lam Oct 20 '11 at 14:39
  • With your first version of `checkArrays()`: `checkArrays([11,22,33,44], [1,12,23,344]) // true` – Ja͢ck Feb 22 '13 at 02:41
  • whoops, should be joined with a separator. :) – epascarello Feb 22 '13 at 13:47
  • 3
    This only does work for certain arrays, and will be very slow with big arrays. – Tomáš Zato Mar 21 '13 at 21:01
  • @TomášZato Of course it will be slow with large arrays. Looping over and comparing will be. Thanks for the downvote on a valid answer, the OP did not say they needed super fast performance. – epascarello Mar 21 '13 at 21:55
  • 2
    Generating JSON is looping too, you just (or it seems so) don't know about it. Besides looping, generating JSON also requires more memory - it creates 2 string representations of said arrays before comparing. The downwote function is implemented to order answers from the best to the worst. I think your answer is not a good answer, so I downvoted it. – Tomáš Zato Mar 21 '13 at 22:08
  • @TomášZato Where is the JSON? In small arrays these solutions are perfectly fine and fast for non complex arrays. The second solution can drop the sort() if it is the same thing and it is a simple for loop. – epascarello Mar 21 '13 at 22:17
  • 2
    Sorry, I just said JSON instead of `.join()`. Maybe if you stated your second solution as primary (as it is the better one, though toothless against multidimensional arrays), I would not judge you that way. So far, I downoted all answers that do convert arrays to strings. As well, I upvoted all that use the right way, in case you needed that to know. This means @Tim Down's answer and Bireys one. – Tomáš Zato Mar 21 '13 at 23:01
  • 6
    First version FAILS: `checkArrays([1,2,3] , ["1,2",3]) == true`, and it's very unlikely that that's what you want to happen! – Doin Oct 16 '14 at 03:46
  • @Doin, so use a separator that is unique if you know the array content will contain certain characters. `join("~~!!@@##$$%%^^&&**")` – epascarello Oct 16 '14 at 12:30
  • 2
    @epascarello: Yes, you can but (aside from the inefficiency of the very long separator you suggest) it means there will be edge cases (where the array happens to contain a string with your separator in it) where the checkArrays() function misbehaves. This might not be a problem if you know something about the contents of the arrays (so you can choose a separator you're sure won't be in the array items), but if you're trying to write a *general* array-comparison function, then using `join()` like this makes it subtly buggy! – Doin Oct 17 '14 at 13:49
  • 2
    ...you *could* fix it using some kind of string escaping mechanism, such as replacing "\" with "\\" followed by replacing "," with "\#" (for example), prior to `join()`ing (ensuring that the individual strings to be joined never contain commas). However given the effort and inefficiency of this approach, you'd be much better off just looping through the array elements! – Doin Oct 17 '14 at 13:55
  • Note that `the sort()` call will *modify the input arrays* - this might not be desirable. – try-catch-finally Jul 15 '17 at 08:45
15

In my case compared arrays contain only numbers and strings. This function will show you if arrays contain same elements.

function are_arrs_match(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_match(arr1, arr2)) //true
console.log (are_arrs_match(arr1, arr3)) //false
yesnik
  • 4,085
  • 2
  • 30
  • 25
  • The question doesn't ask you to sort, so your solution is wrong for examples like `are_arrs_equal([1,2], [2,1])`. Also, see other discussions on this page for why stringifying is unnecessary, fragile, and wrong. – Tim has moved to Codidact Aug 03 '16 at 03:31
  • ```are_arrs_equal([1,2], [2,1])``` returns ```true``` as expected. Perhaps this solution is not ideal, but it worked for me. – yesnik Aug 08 '16 at 12:37
  • That's precisely the problem, those two are not equal in any sane sense of the word "equal" for an *ordered* data structure. They're arrays, not sets, and if you want set equality you should call it that -- and be answering a different question. :-) – Tim has moved to Codidact Aug 09 '16 at 19:59
  • You're right! :) I'll rename this method to ```are_arrs_match(arr1, arr2) ```. Yes, it doesn't check equality of arrays, but it can say if they contain the same elements. – yesnik Aug 10 '16 at 09:16
  • 2
    I agree with the comments above, but this solution also works for me in my simple arrays of integers, where order is not important, so I will use it. – tomazahlin Oct 14 '16 at 16:51
  • 1
    Fails for `are_arrs_match([1,2], ["1,2"])` (returns `true`). And note that `the sort()` call will *modify the input arrays* - this might not be desirable. – try-catch-finally Jul 15 '17 at 08:38
14

Even though this has a lot of answers, one that I believe to be of help:

const newArray = [ ...new Set( [...arr1, ...arr2] ) ]

It is not stated in the question how the structure of the array is going to look like, so If you know for sure that you won't have nested arrays nor objects in you array (it happened to me, that's why I came to this answer) the above code will work.

What happens is that we use spread operator ( ... ) to concat both arrays, then we use Set to eliminate any duplicates. Once you have that you can compare their sizes, if all three arrays have the same size you are good to go.

This answer also ignores the order of elements, as I said, the exact situation happened to me, so maybe someone in the same situation might end up here (as I did).


Edit1.

Answering Dmitry Grinko's question: "Why did you use spread operator ( ... ) here - ...new Set ? It doesn't work"

Consider this code:

const arr1 = [ 'a', 'b' ]
const arr2 = [ 'a', 'b', 'c' ]
const newArray = [ new Set( [...arr1, ...arr2] ) ]
console.log(newArray)

You'll get

[ Set { 'a', 'b', 'c' } ]

In order to work with that value you'd need to use some Set properties (see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set). On the other hand, when you use this code:

const arr1 = [ 'a', 'b' ]
const arr2 = [ 'a', 'b', 'c' ]
const newArray = [ ...new Set( [...arr1, ...arr2] ) ]
console.log(newArray)

You'll get

[ 'a', 'b', 'c' ]

That's the difference, the former would give me a Set, it would work too as I could get the size of that Set, but the latter gives me the array I need, what's more direct to the resolution.

  • Why did you use spread operator ( ... ) here - ...new Set ? It doesn't work. – Dmitry Grinko Nov 09 '17 at 19:34
  • Dmitry Grinko I believe I answered your question on my Edit1. But I'm not sure what you meant by saying 'it doesn't work', as both answers can get you in the way – Jeferson Euclides Nov 10 '17 at 11:37
  • 1
    [1, 2, 2, 3], [1, 2, 2, 3] < doesn't this simply fail with the case? The resulting set will have a length not the same as the inputs. – Leo Lei Sep 17 '20 at 08:48
  • @LeoLei you are correct, as explained in the post this is very specific to certain situations. I used it when I was comparing DB responses, I knew I wouldn't have a situation similar to what you mentioned. – Jeferson Euclides Dec 16 '20 at 17:00
  • 1
    Nice! I was looking for sth along these lines. This should have way more votes. Upvoting – EigenFool Sep 05 '22 at 10:18
12

Shortest

For an array of numbers try:

a1==''+a2

var a1 = [1,2,3];
var a2 = [1,2,3];

console.log( a1==''+a2 )

Note: this method will not work when the array also contains strings, e.g. a2 = [1, "2,3"].

Kamil Kiełczewski
  • 85,173
  • 29
  • 368
  • 345
12

You can simply use isEqual from lodash library. It is very efficient and clean.

import isEqual from "lodash/isEqual";

const isTwoArraysEqual = isEqual(array1, array2);
Hamza Hmem
  • 502
  • 5
  • 11
9

Your code will not handle the case appropriately when both arrays have same elements but not in same order.

Have a look at my code with your example which compares two arrays whose elements are numbers, you might modify or extend it for other element types (by utilising .join() instead of .toString()).

var a1 = [1,2,3];
var a2 = [1,2,3];
const arraysAreEqual = a1.sort().toString()==a2.sort().toString();
// true if both arrays have same elements else false
console.log(arraysAreEqual);
9

Here you go,

const a = [1, 2, 3]
const b = [1, 2, 3, 4, 5]

const diff = b.filter(e => !a.includes(e))
console.log(diff)

Most of the above answers dosen't work for unordered list. This works for unordered lists too.

const a = [3, 2, 1]
const b = [1, 2, 3, 4, 5]

const diff = b.filter(e => !a.includes(e))
console.log(diff)

If size of a is greater than b,

const a = [1, 2, 3, 4, 5]
const b = [3, 2, 1]

const diff = a.length > b.length ? a.filter(e => !b.includes(e)) : b.filter(e => !a.includes(e))
console.log(diff)
Aditya
  • 117
  • 1
  • 3
  • The above solution tries to find numbers in a [1,2,3] that aren't present in b [3,2,3], for your case, all of the unique numbers in b (2,3) are present in a (1,2,3), and that's why its printing an empty array. – Aditya May 11 '22 at 12:21
  • 1
    @AkshayVijayJain , you could compare the length of arrays, const diff = a.length > b.length ? a.filter(e => !b.includes(e)) : b.filter(e => !a.includes(e)) – Aditya Jun 18 '22 at 09:47
9

There are many complicated long answers in here, so I just want to contribute one very simple answer: use toString() to turn an array into a simple comma-separated string which you can easily compare with ===

let a = [1, 2, 3]
let b = [1, 2, 3]
let c = [4, 2, 3]

console.log(a.toString())  // this outputs "1,2,3"
console.log(a.toString() === b.toString())  // this outputs true because "1,2,3" === "1,2,3"
console.log(a.toString() === c.toString())  // this outputs false because "1,2,3" != "4,2,3"
michaels234
  • 119
  • 1
  • 3
  • This is not a good approach in the case in which the second array has the same value but different indexes. `1,2,3` !== `3,2,1`. So maybe you need to sort the arrays first. – Spleen Apr 16 '22 at 08:38
  • I am wondering how could someone vote this answer, it will not work, when order of elements is different – Akshay Vijay Jain Jun 15 '22 at 01:17
  • 2
    Because usually order of elements is important, and 2 different arrays with different orders of elements are not the same. You can't use them the same or access them with the same indices etc. – michaels234 Jun 16 '22 at 04:47
8

Code Golfing

There are plenty of answers showing how to compare arrays efficiently.

Below is the shortest way to compare two int or (string) arrays, measured in bytes of code.

const a = [1, 2, 3]
const b = [1, 2, 3]

console.log("1. ", a.join() == b.join())
console.log("2. ", a.join() == [].join())

console.log("3. ", 1 + a == 1 + b)
console.log("4. ", 1 + [] == 1 + b)

// even shorter
console.log("4. b) ", a == "" + b)

// false positives (see flaws)
console.log("5. ", 1 + ["3"] == 1 + [3]) // type differences
console.log("6. ", 1 + ["1,2"] == 1 + ["1", "2"])

Explanation

This works because when using the + operator, the types are automatically converted to allow concatenation. In this case, the 1 and the [1, 2, 3] are both converted to a string.

Internally, JavaScript uses [1, 2, 3].join() to convert the array to a string and then adds them resulting in 11,2,3. When doing this on both arrays, one can simply use === or == to compare the two strings.

Flaws

Using this technique, the comparison does not care if the elements in the arrays to be compared are of different types. [1, 2] will be equal to ["1", "2"] because of the string conversion.

EDIT: As pointed out in the comments, comparing string arrays can produce false positives, such as ["1,2"] being 'equal' to ["1", "2"]. This is of no concern if you are sure these never occur (e.g. in many code golfing challenges).

Disclaimer

While this is useful for code golfing, it should probably not be used in production code. The two flaws pointed out aren't helping that either.

swift-lynx
  • 3,219
  • 3
  • 26
  • 45
8

Lot of good answers here. This is how I usually do it -

if ( arr1.length === arr2.length && arr1.every((a1) => arr2.includes(a1)) ) {
   // logic
}

every() will only return true if all elements pass the given camparison logic. If it encounters a false, in any iteration, it terminates and returns false.

Time complexity will be O(n*m).

Ankit Kumar
  • 97
  • 2
  • 9
7

Here is a Typescript version:

//https://stackoverflow.com/a/16436975/2589276
export function arraysEqual<T>(a: Array<T>, b: Array<T>): boolean {
    if (a === b) return true
    if (a == null || b == null) return false
    if (a.length != b.length) return false

    for (var i = 0; i < a.length; ++i) {
        if (a[i] !== b[i]) return false
    }
    return true
}

//https://stackoverflow.com/a/16436975/2589276
export function arraysDeepEqual<T>(a: Array<T>, b: Array<T>): boolean {
    return JSON.stringify(a) === JSON.stringify(b)
}

Some test cases for mocha:

it('arraysEqual', function () {
    let a = [1,2]
    let b = [1,2]
    let c = [2,3]
    let d = [2, 3]
    let e = ['car','apple','banana']
    let f = ['car','apple','banana']
    let g = ['car','apple','banan8']

    expect(arraysEqual(a, b)).to.equal(true)
    expect(arraysEqual(c, d)).to.equal(true)
    expect(arraysEqual(a, d)).to.equal(false)
    expect(arraysEqual(e, f)).to.equal(true)
    expect(arraysEqual(f, g)).to.equal(false)
})

it('arraysDeepEqual', function () {
    let a = [1,2]
    let b = [1,2]
    let c = [2,3]
    let d = [2, 3]
    let e = ['car','apple','banana']
    let f = ['car','apple','banana']
    let g = ['car','apple','banan8']
    let h = [[1,2],'apple','banan8']
    let i = [[1,2],'apple','banan8']
    let j = [[1,3],'apple','banan8']

    expect(arraysDeepEqual(a, b)).to.equal(true)
    expect(arraysDeepEqual(c, d)).to.equal(true)
    expect(arraysDeepEqual(a, d)).to.equal(false)
    expect(arraysDeepEqual(e, f)).to.equal(true)
    expect(arraysDeepEqual(f, g)).to.equal(false)
    expect(arraysDeepEqual(h, i)).to.equal(true)
    expect(arraysDeepEqual(h, j)).to.equal(false)
})
Esqarrouth
  • 38,543
  • 21
  • 161
  • 168
7

There is a Stage 1 proposal, introduced in 2020, to allow for the easy comparison of arrays by adding Array.prototype.equals to the language. This is how it would work, without any libraries, monkeypatching, or any other code:

[1, 2, 3].equals([1, 2, 3]) // evaluates to true
[1, 2, undefined].equals([1, 2, 3]) // evaluates to false
[1, [2, [3, 4]]].equals([1, [2, [3, 4]]]) // evaluates to true

It's only a tentative proposal so far - TC39 will now "devote time to examining the problem space, solutions and cross-cutting concerns". If it makes it to stage 2, it has a good chance of eventually being integrated into the language proper.

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
6

If you are using a testing framework like Mocha with the Chai assertion library, you can use deep equality to compare arrays.

expect(a1).to.deep.equal(a2)

This should return true only if the arrays have equal elements at corresponding indices.

metakermit
  • 21,267
  • 15
  • 86
  • 95
6

If they are two arrays of numbers or strings only, this is a quick one-line one

const array1 = [1, 2, 3];
const array2 = [1, 3, 4];
console.log(array1.join(',') === array2.join(',')) //false

const array3 = [1, 2, 3];
const array4 = [1, 2, 3];
console.log(array3.join(',') === array4.join(',')) //true
Gaizka Allende
  • 9,228
  • 4
  • 21
  • 16
  • const array1 = [1]; const array2 = [1, 1]; console.log(array1.join('') === array2.join('')) //returns true – Dan M. May 07 '17 at 17:58
  • it shouldn't: array1.join('') is '1' and array2.join('') is '11' – Gaizka Allende May 09 '17 at 05:27
  • sorry, typo. The first array should be `[11]`. Pretty obvious as to why this happens and how to fix. – Dan M. May 10 '17 at 02:21
  • Not sure what you're about, it's pretty simple: [1].join() is "1" and [1,1].join() is "1,1", so they'll never be equal – Gaizka Allende May 11 '17 at 15:01
  • please, read my comment again more carefully. If you still don't see it, please take a loot at http://ideone.com/KFu427 – Dan M. May 11 '17 at 15:24
  • const a1 = [1, 1, 21]; const a2 = [11, 21]; console.log(a1.join('') === a2.join('')) // returns true. The given solution would work only for array consisting of single digits. – Richie Jun 10 '17 at 03:59
  • that's right!! :)) just add a character to the join method const array1 = [1, 1, 21]; const array1 = [11, 21]; console.log(array7.join(',') === array8.join(',')) //false – Gaizka Allende Jun 12 '17 at 11:47
  • 1
    Fails for `[1,2]` and `["1,2"]`. – try-catch-finally Jul 15 '17 at 08:43
  • true but that is really out of question – Gaizka Allende Nov 09 '18 at 18:17
  • If you have two arrays of 10K items each and the first elements in both are already different you would still serialise both before you compare them whereas you could have stopped the comparison with a simple `a[0] !== b[0]`. Have you compared your approach against a classic iteration for example? Besides OP didn't exactly rule out things like objects or nested arrays. Here's an example where serialisation would fail: `[{a:1}].join('') === [{b:2}].join('')` – customcommander Sep 08 '20 at 07:00
5

Another approach with very few code (using Array reduce and Array includes):

arr1.length == arr2.length && arr1.reduce((a, b) => a && arr2.includes(b), true)

If you want to compare also the equality of order:

arr1.length == arr2.length && arr1.reduce((a, b, i) => a && arr2[i], true)
  • The length check ensures that the set of elements in one array isn't just a subset of the other one.

  • The reducer is used to walk through one array and search for each item in other array. If one item isn't found the reduce function returns false.

    1. In the first example it's being tested that an element is included
    2. The second example check for the order too
try-catch-finally
  • 7,436
  • 6
  • 46
  • 67
DEls
  • 241
  • 3
  • 14
4

We could do this the functional way, using every (https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/every)

function compareArrays(array1, array2) {
    if (array1.length === array2.length)
        return array1.every((a, index) => a === array2[index])
    else
        return false
}

// test
var a1 = [1,2,3];
var a2 = [1,2,3];

var a3 = ['a', 'r', 'r', 'a', 'y', '1']
var a4 = ['a', 'r', 'r', 'a', 'y', '2']

console.log(compareArrays(a1,a2)) // true
console.log(compareArrays(a1,a3)) // false
console.log(compareArrays(a3,a4)) // false
peonicles
  • 1,607
  • 2
  • 20
  • 28
  • Doesn't work if we want arr1 == arr2 if all the data of arr1 is in arr2 and vice versa, doesn't matter in what order. – Ankit Kumar Jun 28 '22 at 01:17
4

This compares 2 unsorted arrays:

function areEqual(a, b) {
  if ( a.length != b.length) {
    return false;
  }
  return a.filter(function(i) {
    return !b.includes(i);
  }).length === 0;  
}
4

A simple approach:

function equals(a, b) {
    if ((a && !b) || (!a && b) || (!a && !b) || (a.length !== b.length)) {
        return false;
    }

    var isDifferent = a.some(function (element, index) { 
        return element !== b[index];
    });

    return !isDifferent;
}
Pedro Rodrigues
  • 1,662
  • 15
  • 19
4

Already some great answers.But i would like to share anther idea which has proven to be reliable in comparing arrays. We can compare two array using JSON.stringify ( ) . It will create a string out the the array and thus compare two obtained strings from two array for equality

JSON.stringify([1,{a:1},2]) == JSON.stringify([1,{a:1},2]) //true

JSON.stringify([1,{a:1},2]) == JSON.stringify([1,{a:2},2]) //false

JSON.stringify([1,{a:1},2]) == JSON.stringify([1,{a:2},[3,4],2]) //false

JSON.stringify([1,{a:1},[3,4],2]) == JSON.stringify([1,{a:2},[3,4],2]) //false

JSON.stringify([1,{a:2},[3,4],2]) == JSON.stringify([1,{a:2},[3,4],2]) //true

JSON.stringify([1,{a:2},[3,4],2]) == JSON.stringify([1,{a:2},[3,4,[5]],2]) //false

JSON.stringify([1,{a:2},[3,4,[4]],2]) == JSON.stringify([1,{a:2},[3,4,[5]],2]) //false

JSON.stringify([1,{a:2},[3,4,[5]],2]) == JSON.stringify([1,{a:2},[3,4,[5]],2]) //true
AL-zami
  • 8,902
  • 15
  • 71
  • 130
4
In a simple way uning stringify but at same time thinking in complex arrays:

**Simple arrays**:  
var a = [1,2,3,4];  
var b = [4,2,1,4];  
JSON.stringify(a.sort()) === JSON.stringify(b.sort()) // true  

**Complex arrays**:  
var a = [{id:5,name:'as'},{id:2,name:'bes'}];  
var b = [{id:2,name:'bes'},{id:5,name:'as'}];  
JSON.stringify(a.sort(function(a,b) {return a.id - b.id})) === JSON.stringify(b.sort(function(a,b) {return a.id - b.id})) // true  

**Or we can create a sort function**  

function sortX(a,b) {  
return a.id -b.id; //change for the necessary rules  
}  
JSON.stringify(a.sort(sortX)) === JSON.stringify(b.sort(sortX)) // true  
4

Here a possibility for unsorted arrays and custom comparison:

    const array1 = [1,3,2,4,5];
    const array2 = [1,3,2,4,5];
    
    const isInArray1 = array1.every(item => array2.find(item2 => item===item2))
    const isInArray2 = array2.every(item => array1.find(item2 => item===item2))
    
    const isSameArray = array1.length === array2.length && isInArray1 && isInArray2
    
    console.log(isSameArray); //true
Jöcker
  • 5,281
  • 2
  • 38
  • 44
4

Simple

type Values = number | string;

/** Not sorted array */
function compare<Values>(a1: Array<Values>, a2: Array<Values>): boolean {
    if (a1.length !== a2.length) {
        return false;
    }

    /** Unique values */
    const set1 = new Set<Values>(a1);
    const set2 = new Set<Values>(a2);
    if (set1.size !== set2.size) {
        return false;
    }

    return [...set1].every((value) => [...set2].includes(value));
}

compare([1, 2, 3], [1, 2, 3]);    // true
compare([1, 2, 3], [1, 3, 2]);    // true
compare([1, 1, 1], [1, 2, 3]);    // false
compare([1, 1, 2, 3], [1, 2, 3]); // false

/** Sorted arrays, faster method */
function compareSorted<Values>(a1: Array<Values>, a2: Array<Values>): boolean {
    if (a1.length !== a2.length) {
        return false;
    }

    /** Unique values */
    const set1 = new Set<Values>(a1);
    const set2 = new Set<Values>(a2);
    if (set1.size !== set2.size) {
        return false;
    }

    return [...set1].every((value, index) => value === [...set2][index]);
}

compareSorted([1, 2, 3], [1, 2, 3]);    // true
compareSorted([1, 2, 3], [1, 3, 2]);    // false
compareSorted([1, 1, 1], [1, 2, 3]);    // false
compareSorted([1, 1, 2, 3], [1, 2, 3]); // false
Filip Seman
  • 1,252
  • 2
  • 15
  • 22
3

Herer's my solution:

/**
 * Tests two data structures for equality
 * @param {object} x
 * @param {object} y
 * @returns {boolean}
 */
var equal = function(x, y) {
    if (typeof x !== typeof y) return false;
    if (x instanceof Array && y instanceof Array && x.length !== y.length) return false;
    if (typeof x === 'object') {
        for (var p in x) if (x.hasOwnProperty(p)) {
            if (typeof x[p] === 'function' && typeof y[p] === 'function') continue;
            if (x[p] instanceof Array && y[p] instanceof Array && x[p].length !== y[p].length) return false;
            if (typeof x[p] !== typeof y[p]) return false;
            if (typeof x[p] === 'object' && typeof y[p] === 'object') { if (!equal(x[p], y[p])) return false; } else
            if (x[p] !== y[p]) return false;
        }
    } else return x === y;
    return true;
};

Works with any nested data structure, and obviously ignores objects' methods. Don't even think of extending Object.prototype with this method, when I tried this once, jQuery broke ;)

For most arrays it's still faster than most of serialization solutions. It's probably the fastest compare method for arrays of object records.

Harry
  • 4,524
  • 4
  • 42
  • 81
  • no good! these give true: `equal({}, {a:1})` and `equal({}, null)` and this errors out: `equal({a:2}, null)` – kristianlm Feb 03 '17 at 13:05
3
JSON.stringify(collectionNames).includes(JSON.stringify(sourceNames)) ?  array.push(collection[i]) : null

This is how i did it.

Leed
  • 263
  • 2
  • 4
  • 11
  • Good solution - but I wonder in certain situations if it will not always work as intended, such as with certain primitives or deeply nested arrays? I hope it works in all circumstances though – Ben Rondeau Dec 13 '17 at 21:37
3

I know that JSON.stringfy is slow when dealing with large datasets but what if you used template literals?

Example:

const a = [1, 2, 3];
const b = [1, 2, 'test'];

const a_string = Array.isArray(a) && `${a}`;
const b_string = Array.isArray(b) && `${b}`;

const result = (a === b);

console.log(result);

Taking into consideration you're using ES6 of course.

=)

0xe1λ7r
  • 1,957
  • 22
  • 31
  • Beware, this comparison will also work for an array compared to a string. – Elias Dorneles May 01 '20 at 19:53
  • @EliasDorneles, Thanks a bunch! I updated my answer to perform a check before assigning the variable to a template string literals. – 0xe1λ7r May 02 '20 at 08:58
  • Hehe, now it will say these two are equal `a = ["1,1", "2"]` and `b = [1,1,2]` (or `b = ["1", "1,2"]`)... I think it will be hard to get something robust with this approach. ^^ – Elias Dorneles May 02 '20 at 10:19
  • Javascript is a loosely typed language :). So in my opinion, if that was the case then I'd opt for something like [typescript](https://www.typescriptlang.org/) or [flow](https://flow.org/). XD – 0xe1λ7r May 04 '20 at 10:16
  • This also doesn't work reliably when the array contains objects, where OTOH `JSON.stringify` won't perform a shallow comparison either. – mycroes Oct 13 '20 at 08:41
3

An alternative way using filter and arrow functions

arrOne.length === arrTwo.length && arrOne.filter((currVal, idx) => currVal !== arrTwo[idx]).length === 0
jpthesolver2
  • 1,107
  • 1
  • 12
  • 22
3

It's a tricky implicit array equality checking but can handle the job right after coherence arrays to string.

var a1 = [1, 2, 3];
var a2 = [1, 2, 3];
var isEqual = a1 <= a2 && a1 >= a2; // true
Penny Liu
  • 15,447
  • 5
  • 79
  • 98
movAhed
  • 73
  • 1
  • 2
  • 14
2

Extending Tomáš Zato idea. Tomas's Array.prototype.compare should be infact called Array.prototype.compareIdentical.

It passes on:

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

But fails on:

[[1, 2, [3, 2]],1, 2, [3, 2]].compareIdentical([1, 2, [3, 2],[1, 2, [3, 2]]])

Here is better (in my opinion) version:

Array.prototype.compare = 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;

    this.sort();
    array.sort();
    for (var i = 0; i < this.length; i++) {
        // Check if we have nested arrays
        if (this[i] instanceof Array && array[i] instanceof Array) {
            // recurse into the nested arrays
            if (!this[i].compare(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;
}

http://jsfiddle.net/igos/bcfCY/

Igor S.
  • 3,332
  • 1
  • 25
  • 33
  • 2
    -1. If it 'fails' on the example you've given, then that's only the case for a somewhat arbitrary definition of 'fails'. Why would you expect those two different arrays to be considered equal? You haven't even explained what concept of 'equality' you're trying to implement here, or why it's a sensible or helpful one, but it looks like you want multidimensional arrays to be compared as if they were collapsed down to single-dimensional ones. If so, you didn't even achieve that: [1,2].compare([[1,2]]) gives false with your version, just as with Tomáš's. – Mark Amery Jun 08 '13 at 13:57
  • Based on what I could infer, he's saying that [1, 2, 3, 4] and [1, 3, 2, 4] should be compared as equal (Order doesn't matter). – Gautham Badhrinathan Jul 03 '13 at 08:50
2
var a1 = [1,2,3,6];
var a2 = [1,2,3,5];

function check(a, b) {
  return (a.length != b.length) ? false : 
  a.every(function(row, index) {
    return a[index] == b[index];
  });
}  

check(a1, a2);

////// OR ///////

var a1 = [1,2,3,6];
var a2 = [1,2,3,6];

function check(a, b) {
  return (a.length != b.length) ? false : 
  !(a.some(function(row, index) {
    return a[index] != b[index];
  }));
}  

check(a1, a2)
Vasanth
  • 212
  • 1
  • 8
  • You can you some function as well which will not iterate completely if we get the required condition satisfied, like above – Vasanth Mar 08 '17 at 14:42
2

Recursive & works on NESTED arrays:

function ArrEQ(a1,a2){
   return( 
        //:Are both elements arrays?
        Array.isArray(a1)&&Array.isArray(a2) 
        ?
        //:Yes: Test each entry for equality:
        a1.every((v,i)=>(ArrEQ(v,a2[i])))
        :
        //:No: Simple Comparison:
        (a1===a2)
   );;
};;

console.log( "Works With Nested Arrays:" );
console.log( ArrEQ( 
    [1,2,3,[4,5,[6,"SAME/IDENTICAL"]]],
    [1,2,3,[4,5,[6,"SAME/IDENTICAL"]]]
));;     
console.log( ArrEQ( 
    [1,2,3,[4,5,[6,"DIFFERENT:APPLES" ]]],
    [1,2,3,[4,5,[6,"DIFFERENT:ORANGES"]]]
));;  
KANJICODER
  • 3,611
  • 30
  • 17
2

Works with MULTIPLE arguments with NESTED arrays:

//:Return true if all of the arrays equal.
//:Works with nested arrays.
function AllArrEQ(...arrays){
    for(var i = 0; i < (arrays.length-1); i++ ){
        var a1 = arrays[i+0];
        var a2 = arrays[i+1];
        var res =( 
            //:Are both elements arrays?
            Array.isArray(a1)&&Array.isArray(a2) 
            ?
            //:Yes: Compare Each Sub-Array:
            //:v==a1[i]
            a1.every((v,i)=>(AllArrEQ(v,a2[i])))
            :
            //:No: Simple Comparison:
            (a1===a2)
        );;
        if(!res){return false;}
    };;
    return( true );
};;

console.log( AllArrEQ( 
        [1,2,3,[4,5,[6,"ALL_EQUAL"   ]]],
        [1,2,3,[4,5,[6,"ALL_EQUAL"   ]]],
        [1,2,3,[4,5,[6,"ALL_EQUAL"   ]]],
        [1,2,3,[4,5,[6,"ALL_EQUAL"   ]]],
));; 
KANJICODER
  • 3,611
  • 30
  • 17
2

I believe in plain JS and with ECMAScript 2015, which is sweet and simple to understand.

var is_arrays_compare_similar = function (array1, array2) {

    let flag = true;

    if (array1.length == array2.length) {

        // check first array1 object is available in array2 index
        array1.every( array_obj => {
            if (flag) {
                if (!array2.includes(array_obj)) {
                    flag = false;
                }
            }
        });
        
        // then vice versa check array2 object is available in array1 index
        array2.every( array_obj => {
            if (flag) {
                if (!array1.includes(array_obj)) {
                    flag = false;
                }
            }
        });

        return flag;
    } else {
        return false;
    }
    
}
Nimantha
  • 6,405
  • 6
  • 28
  • 69
ArifMustafa
  • 4,617
  • 5
  • 40
  • 48
  • 7
    Why is the vice versa check needed? We know the arrays are the same size, so if every item in array1 is also found in array2; why would we then have to check that every item in array2 is also in array1? – JeffryHouser Nov 02 '19 at 18:47
  • First array could be [1,1] second [1,2] without vice versa this cannot be detected – Tommy Grovnes Oct 09 '21 at 12:56
2

Surprisingly, nobody brought up a solution with find

const a = [1, 2, 3]
const b = [1, 2, 3, 4]
a.find((v,i) => v !== b[i])

The benefit here is that instead of comparing all values it looks for the first occurrence and ends the loop as early as possible. Or in other words, instead of asking "are two arrays equal?" it asks "is one array different from another?".

3rd by performance benchmark https://jsben.ch/TgFrA

Keep in mind, the order matters, a.find(...) !== b.find(...) and could be checked by a.length === b.length

if (a.length === b.length && a.find((v,i) => v !== b[i]) === undefined) {
  // equal
}
Mihailoff
  • 577
  • 5
  • 6
  • 3
    `a.find((v,i) => v !== b[i])` is exactly equivalent to `a.some((v,i) => v !== b[i])` with the difference that `.some()` returns a boolean directly. `.some()` and `.every()` are also equivalent to each other through negation: `a.every((v,i) => v -== b[i])`. When I ran the benchmark the `.every()` code was in second place in front of the `.find()` variant. – VLAZ Nov 04 '21 at 05:41
1

Actually, in the Lodash documentation, they give two pretty good examples for comparing and return fresh arrays for both differences and similarities (respectively in the examples below):

import { differenceWith, intersectionWith, isEqual } from 'lodash'

differenceWith(
  [{ a: 1 }, { b: 1 }],
  [{ a: 1 }, { b: 1 }, { c: 1 }],
  isEqual
) // []... the bigger array needs to go first!

differenceWith(
  [{ a: 1 }, { b: 1 }, { c: 1 }],
  [{ a: 1 }, { b: 1 }],
  isEqual,
) // [{ c: 1 }] 

intersectionWith(
  [{ a: 1 }, { b: 1 }],
  [{ a: 1 }, { b: 1 }, { c: 1 }],
  isEqual,
) // [{ a: 1 }, { b: 1 }] this one doesn't care about which is bigger

If you won't always know which array will be bigger, you can write a helper function for it like so:

const biggerFirst = (arr1, arr2) => {
  return arr1.length > arr2.length ? [arr1, arr2] : [arr2, arr1]
}

const [big, small] = biggerFirst(
  [{ a: 1 }, { b: 1 }],
  [{ a: 1 }, { b: 1 }, { c: 1 }],
)

differenceWith(big, small, isEqual) // even though we have no idea which is bigger when they are fed to biggerFirst()

From what I can tell, these match deeply as well so that's pretty nice.

I know relying on libraries for everything shouldn't be applauded, but this is the most concise/clean solution I've found to a really common problem. Hope it helps someone!

corysimmons
  • 7,296
  • 4
  • 57
  • 65
1

All the other solutions look complicated. This might not be the most efficient with or handle all edge cases but it works great for me.

Array.prototype.includesArray = function(arr) {
  return this.map(i => JSON.stringify(i)).includes(JSON.stringify(arr))
}

Usage

[[1,1]].includesArray([1,1])
// true

[[1,1]].includesArray([1,1,2])
// false
Collin Thomas
  • 1,590
  • 1
  • 13
  • 12
  • This is very inneficient, and will produce an arror if any of these arrays contains a recursive structure or something otherwise non-serializable. – Domino Jun 14 '22 at 18:06
0

this script compares Object, Arrays and multidimensional array

function compare(a,b){
     var primitive=['string','number','boolean'];
     if(primitive.indexOf(typeof a)!==-1 && primitive.indexOf(typeof a)===primitive.indexOf(typeof b))return a===b;
     if(typeof a!==typeof b || a.length!==b.length)return false;
     for(i in a){
          if(!compare(a[i],b[i]))return false;
     }
     return true;
}

first line checks whether it's a primitive type. if so it compares the two parameters.

if they are Objects. it iterates over the Object and check every element recursivly.

Usage:

var a=[1,2,[1,2]];
var b=[1,2,[1,2]];
var isEqual=compare(a,b);  //true
Omar Elawady
  • 3,300
  • 1
  • 13
  • 17
0

This function compares two arrays of arbitrary shape and dimesionality:

function equals(a1, a2) {

    if (!Array.isArray(a1) || !Array.isArray(a2)) {
        throw new Error("Arguments to function equals(a1, a2) must be arrays.");
    }

    if (a1.length !== a2.length) {
        return false;
    }

    for (var i=0; i<a1.length; i++) {
        if (Array.isArray(a1[i]) && Array.isArray(a2[i])) {
            if (equals(a1[i], a2[i])) {
                continue;
            } else {
                return false;
            }
        } else {
            if (a1[i] !== a2[i]) {
                return false;
            }
        }
    }

    return true;
}
chessweb
  • 4,613
  • 5
  • 27
  • 32
0

tried deep-equal and it worked

var eq = require('deep-equal');
eq({a: 1, b: 2, c: [3, 4]}, {c: [3, 4], a: 1, b: 2});
d9k
  • 1,476
  • 3
  • 15
  • 28
0

With an option to compare the order or not:

function arraysEqual(a1, a2, compareOrder) {
    if (a1.length !== a2.length) {
        return false;
    }

    return a1.every(function(value, index) {
        if (compareOrder) {
            return value === a2[index];
        } else {
            return a2.indexOf(value) > -1;
        }
    });
}
LachoTomov
  • 3,312
  • 30
  • 42
0

Récursive cmp function working with number/string/array/object

<script>
var cmp = function(element, target){

   if(typeof element !== typeof target)
   {
      return false;
   }
   else if(typeof element === "object" && (!target || !element))
   {
      return target === element;
   }
   else if(typeof element === "object")
   {
       var keys_element = Object.keys(element);
       var keys_target  = Object.keys(target);
       
       if(keys_element.length !== keys_target.length)
       {
           return false;
       }
       else
       {
           for(var i = 0; i < keys_element.length; i++)
           {
                if(keys_element[i] !== keys_target[i])
                    return false;
                if(!cmp(element[keys_element[i]], target[keys_target[i]]))
                    return false;
           }
     return true;
       }
   }
   else
   {
       return element === target;

   }
};

console.log(cmp({
    key1: 3,
    key2: "string",
    key3: [4, "45", {key4: [5, "6", false, null, {v:1}]}]
}, {
    key1: 3,
    key2: "string",
    key3: [4, "45", {key4: [5, "6", false, null, {v:1}]}]
})); // true

console.log(cmp({
    key1: 3,
    key2: "string",
    key3: [4, "45", {key4: [5, "6", false, null, {v:1}]}]
}, {
    key1: 3,
    key2: "string",
    key3: [4, "45", {key4: [5, "6", undefined, null, {v:1}]}]
})); // false
</script>
Daphoque
  • 4,421
  • 1
  • 20
  • 31
0

This method is one that only works on scalar arrays, like the second voted answer on this question.

var arrs = [
  [[1, 2, 3], [1, 2, 3]], // true
  [[1, 2, 3, 4], [1, 2, 3]], // false
  [[1, 2, 3], [1, 2, 3, 4]], // false
]

const arraysEqual = (one, two) => (one.filter((i, n) => two[n] === i).length === one.length) && (two.filter((i, n) => one[n] === i).length === two.length)

arrs.forEach(arr => {
  console.log(arraysEqual(arr[0], arr[1]))
})

Without ES6 syntax:

var arrs = [
  [[1, 2, 3], [1, 2, 3]], // true
  [[1, 2, 3, 4], [1, 2, 3]], // false
  [[1, 2, 3], [1, 2, 3, 4]], // false
]

function arraysEqual(one, two) {
  return (one.filter((i, n) => two[n] === i).length === one.length) && (two.filter((i, n) => one[n] === i).length === two.length)
}

arrs.forEach(arr => {
  console.log(arraysEqual(arr[0], arr[1]))
})
shreyasm-dev
  • 2,711
  • 5
  • 16
  • 34
0

I answered this question at https://stackoverflow.com/a/10316616/711085 (which has since been marked a duplicate of this answer). There you will find a Deep Equals implementation that handles numerous cases, such as Map and Set and arbitrary nesting of arrays and objects. The discussion therein of non-transitivity of == and documenting == vs === is particularly important.


For OP's particular problem, if the arrays consist only of numbers and strings and booleans, and no NaNs, then the most efficient method for sufficiently large arrays is a precompiled function:

function areSimpleArraysEqual(a,b) {
    // requires inputs be arrays of only Number, String, Boolean, and no NaN.
    // will propagate error if either array is undefined.
    if (a.length!=b.length)
        return false;
    for(let i=0; i<a.length; i++)
        if (a[i]!==b[i]) // using === equality
            return false;
    return true;
}

One may achieve average-case O(1) and worst-case O(N) in some rare instances if one's business logic keeps appending to the ends of the arrays, by also checking if (a.length>0 && a[a.length-1]!==b[b.length-1]) return false; .

ninjagecko
  • 88,546
  • 24
  • 137
  • 145
  • 1
    I find it unbelievable that such a widely used language is missing such an essential operation. Python and some other languages are more sane (a==b is true if a and b are arrays with the same elements in the same order). Identity is a different question (a is b in Python). BTW, this thread is conflating lists and sets. Sets are equal if they have the same elements, but for a list/array the elements must be in the same order for equality. – julie Apr 24 '22 at 19:43
0

If you like simple savagery:

const a1 = ['a', 'b', 'e', 'd', 'c'];
const a2 = ['a', 'b', 'c', 'd', 'e'];

a1.length === a2.length && [...a1, ...a2].filter((item) => a2.indexOf(item) === -1).length === 0

Note that you can perform "indexOf" on any of the 2 arrays.

Julien Duris
  • 119
  • 5
  • I guess I get downvotes because this solution does not assert keys are ordered in the same fashion. OP did not specify it precisely, I guess I could have derived it from the term "identical". Nonetheless, this solution proves to be very useful, for an array of "primitives", and is quite efficient compared to other solutions. – Julien Duris Aug 08 '23 at 18:41
-1

My solution compares Objects, not Arrays. This would work in the same way as Tomáš's as Arrays are Objects, but without the Warning:

Object.prototype.compare_to = function(comparable){
    
    // Is the value being compared an object
    if(comparable instanceof Object){
        
        // Count the amount of properties in @comparable
        var count_of_comparable = 0;
        for(p in comparable) count_of_comparable++;
        
        // Loop through all the properties in @this
        for(property in this){
            
            // Decrements once for every property in @this
            count_of_comparable--;
            
            // Prevents an infinite loop
            if(property != "compare_to"){
                
                // Is the property in @comparable
                if(property in comparable){
                    
                    // Is the property also an Object
                    if(this[property] instanceof Object){
                        
                        // Compare the properties if yes
                        if(!(this[property].compare_to(comparable[property]))){
                            
                            // Return false if the Object properties don't match
                            return false;
                        }
                    // Are the values unequal
                    } else if(this[property] !== comparable[property]){
                        
                        // Return false if they are unequal
                        return false;
                    }
                } else {
                
                    // Return false if the property is not in the object being compared
                    return false;
                }
            }
        }
    } else {
        
        // Return false if the value is anything other than an object
        return false;
    }
    
    // Return true if their are as many properties in the comparable object as @this
    return count_of_comparable == 0;
}
Nimantha
  • 6,405
  • 6
  • 28
  • 69
user1877408
  • 137
  • 1
  • 11
-1

Here's a CoffeeScript version, for those who prefer that:

Array.prototype.equals = (array) ->
  return false if not array # if the other array is a falsy value, return
  return false if @length isnt array.length # compare lengths - can save a lot of time

  for item, index in @
    if item instanceof Array and array[index] instanceof Array # Check if we have nested arrays
      if not item.equals(array[index]) # recurse into the nested arrays
        return false
    else if this[index] != array[index]
      return false # Warning - two different object instances will never be equal: {x:20} != {x:20}
  true

All credits goes to @tomas-zato.

Martin
  • 2,302
  • 2
  • 30
  • 42
-1

If the array is plain and the order is matter so this two lines may help

//Assume
var a = ['a','b', 'c']; var b = ['a','e', 'c'];  

if(a.length !== b.length) return false;
return !a.reduce(
  function(prev,next,idx, arr){ return prev || next != b[idx] },false
); 

Reduce walks through one of array and returns 'false' if at least one element of 'a' is nor equial to element of 'b' Just wrap this into function

Serge
  • 665
  • 1
  • 4
  • 15
  • map, reduce, filter everything! :P – Thoran Jul 16 '16 at 12:56
  • 1
    This is a bad solution because `Array.prototype.reduce` will walk through every element in `a` even if the first compared elements do not match. Also using `!a` and `!=` in the loop is a double negative which makes this answer more complicated (and hard to read) than it needs to be – Mulan Aug 07 '16 at 15:39
  • Agree. There is some some() function :) Two years ago i didn't know it. But double negation still will be there. – Serge Aug 08 '16 at 15:58
-1

I would do like this:

[2,3,4,5] == [2,3,4,5].toString()

When you use the "==" operator, javascript check if the values(left and right) is the same type, if it's different javascript try to convert both side in the same type.

Array == String

Array has toString method so javascript use it to convert them to the same type, work the same way writing like this:

[2,3,4,5].toString() == [2,3,4,5].toString()
Victor Castro
  • 267
  • 4
  • 10
-1
let equals = (LHS, RHS) => {
    if (!(LHS instanceof Array)) return "false > L.H.S is't an array";
    if (!(RHS instanceof Array)) return "false > R.H.S is't an array";
    if (LHS.length != RHS.length) return false;
    let to_string = x => JSON.stringify(x.sort((a, b) => a - b));
    return to_string(LHS) == to_string(RHS);
  };

let l = console.log
l(equals([5,3,2],[3,2,5]))    // true
l(equals([3,2,5,3],[3,2,5]))  // false