如何在JavaScript中比较数组?

本文翻译自:How to compare arrays in JavaScript?

I'd like to compare two arrays... ideally, efficiently. 我想比较两个数组...理想地,有效地比较。 Nothing fancy, just true if they are identical, and false if not. 没有幻想,如果相同则为true ,否则为false 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? 每个数组都可以使用JSON编码,但是有没有一种更快或更“更好”的方法来简单地比较数组而不必遍历每个值?


#1楼

参考:https://stackoom.com/question/Wssa/如何在JavaScript中比较数组


#2楼

To compare arrays, loop through them and compare every value: 要比较数组,请遍历它们并比较每个值:

Comparing arrays: 比较数组:

// Warn if overriding existing method
if(Array.prototype.equals)
    console.warn("Overriding existing Array.prototype.equals. Possible causes: New API defines the method, there's a framework conflict or you've got double inclusions in your code.");
// attach the .equals method to Array's prototype to call it on any array
Array.prototype.equals = function (array) {
    // if the other array is a falsy value, return
    if (!array)
        return false;

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

    for (var i = 0, l=this.length; i < l; i++) {
        // Check if we have nested arrays
        if (this[i] instanceof Array && array[i] instanceof Array) {
            // recurse into the nested arrays
            if (!this[i].equals(array[i]))
                return false;       
        }           
        else if (this[i] != array[i]) { 
            // Warning - two different object instances will never be equal: {x:20} != {x:20}
            return false;   
        }           
    }       
    return true;
}
// Hide method from for-in loops
Object.defineProperty(Array.prototype, "equals", {enumerable: false});

Usage: 用法:

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

You may say " But it is much faster to compare strings - no loops... " well, then you should note there ARE loops. 您可能会说“ 但是比较字符串要快得多-没有循环... ”,那么,您应该注意有ARE循环。 First recursive loop that converts Array to string and second, that compares two strings. 第一个递归循环将Array转换为字符串,第二个递归循环比较两个字符串。 So this method is faster than use of string . 因此,此方法比使用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. 但是,请记住,这是用于比较JSON之类的数据,而不是类实例和其他内容。 If you want to compare mor complicated objects, look at this answer and it's superlong function . 如果您想比较复杂的物体,请看这个答案,它是超长函数
To make this work with Array.equals you must edit the original function a little bit: 为了使它与Array.equals一起Array.equals您必须对原始函数进行一些编辑:

...
    // 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 奖励:具有indexOfcontains嵌套数组

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/ Samy Bencherif为您在嵌套数组中搜索特定对象的情况准备了有用的功能,可在以下位置找到: https : //jsfiddle.net/SamyBencherif/8352y6yw/


#3楼

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

#4楼

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 ;) 甚至不用考虑用这种方法扩展Object.prototype,当我尝试过一次时,jQuery坏了;)

For most arrays it's still faster than most of serialization solutions. 对于大多数阵列,它仍然比大多数序列化解决方案要快。 It's probably the fastest compare method for arrays of object records. 对于对象记录数组,这可能是最快的比较方法。


#5楼

Extending Tomáš Zato idea. 扩展TomášZato的想法。 Tomas's Array.prototype.compare should be infact called Array.prototype.compareIdentical. Tomas的Array.prototype.compare实际上应该称为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/ http://jsfiddle.net/igos/bcfCY/


#6楼

Building off Tomáš Zato's answer, I agree that just iterating through the arrays is the fastest. 基于TomášZato的答案,我同意仅迭代数组是最快的。 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 - ie 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. 此函数采用默认为true的strict附加参数。 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: 我还使用该函数和此示例编写了一个快速的jsfiddle:
http://jsfiddle.net/Roundaround/DLkxX/ http://jsfiddle.net/Roundaround/DLkxX/

发布了0 篇原创文章 · 获赞 7 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/asdfgh0077/article/details/105342210