Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to compare contents of javascript array, but not the order of them? [duplicate]

As the title says I want to compare two js arrays in which I only care about the contents being the same, but I don't care about the order of them being the same. So what I would expect is this:

[1, 2, 3, 3] == [1, 2, 3, 3]     // True
[1, 2, 3, 3] == [1, 3, 2, 3]     // True
[1, 2, 3, 3] == [1, 2]           // False
[1, 2, 3, 3] == [1, 2, 3]        // False
[1, 2, 3, 3] == [1, 2, 3, 3, 3]  // False
[1, 2, 3, 3] == [1, "2, 3, 3"]      // False

Obviously the comparison operator doesn't work. From this SO answer I got the Array.prototype method below, but that unfortunately also checks if the order is the same.

So does anybody know how I can check if two js arrays contain the same elements, not taking into account the order of the elements? All tips are welcome!

Array.prototype.equals = function (array) {
    // if the other array is a falsy value, return
    if (!array)
        return false;

    // compare lengths - can save a lot of time 
    if (this.length != array.length)
        return false;

    for (var i = 0, l=this.length; i < l; i++) {
        // Check if we have nested arrays
        if (this[i] instanceof Array && array[i] instanceof Array) {
            // recurse into the nested arrays
            if (!this[i].equals(array[i]))
                return false;       
        }           
        else if (this[i] != array[i]) { 
            // Warning - two different object instances will never be equal: {x:20} != {x:20}
            return false;   
        }           
    }       
    return true;
}   
like image 892
kramer65 Avatar asked Apr 16 '15 11:04

kramer65


2 Answers

sort them before comparing:

from the comment below, if you want the 2 arrs to contain different primitive type.add this sort function.

function s(x,y){
    var pre = ['string' , 'number' , 'bool']
    if(typeof x!== typeof y )return pre.indexOf(typeof y) - pre.indexOf(typeof x);

    if(x === y)return 0;
    else return (x > y)?1:-1;

}
var arr1 = [1, 2, 3, 3].sort(s);
var arr2 = [1, 3, 2, 3].sort(s);

arr1.equals(arr2);// true
like image 105
Omar Elawady Avatar answered Sep 17 '22 23:09

Omar Elawady


Here is a solution that works for primitive values. It uses an object as a primitive map and counts the number of occurrences of each value. However, it also considers the data type of each value.

It checks the length of the arrays first, as shortcut:

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

    var seen = {};
    a.forEach(function(v) {
        var key = (typeof v) + v;
        if (!seen[key]) {
            seen[key] = 0;
        }
        seen[key] += 1;
    });

    return b.every(function(v) {
        var key = (typeof v) + v;
        if (seen[key]) {
            seen[key] -= 1;
            return true;
        }
        // not (anymore) in the map? Wrong count, we can stop here
    });
}
like image 40
Felix Kling Avatar answered Sep 20 '22 23:09

Felix Kling