How to compare arrays in JavaScript?

2018-12-30 22:32发布

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?

30条回答
栀子花@的思念
2楼-- · 2018-12-30 23:21
JSON.stringify(collectionNames).includes(JSON.stringify(sourceNames)) ?  array.push(collection[i]) : null

This is how i did it.

查看更多
何处买醉
3楼-- · 2018-12-30 23:22

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/

查看更多
泪湿衣
4楼-- · 2018-12-30 23:23

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/

查看更多
无与为乐者.
5楼-- · 2018-12-30 23:23

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;  
}
查看更多
初与友歌
6楼-- · 2018-12-30 23:23

Choose each from [a] and loop through all from [b]: Result: 1, 5

var a = [1,4,5,9];
var b = [1,6,7,5];

for (i = 0; i < a.length; i++) {
    for (z = 0; z < a.length; z++) {
        if (a[i] === b[z]) {
            console.log(b[z]); // if match > console.log it 
        }
    }
}
查看更多
几人难应
7楼-- · 2018-12-30 23:26

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.

查看更多
登录 后发表回答