使用jQuery比较两个Javascript对象数组

96
我有两个JavaScript对象数组,我想比较它们是否相同。这些对象在每个数组中的顺序可能不同(大多数情况下会不同)。每个数组不应该超过10个对象。我认为jQuery可能有一个优雅的解决方案来解决这个问题,但我在网上找不到太多信息。
我知道一个嵌套的暴力$.each(array, function(){})解决方案可以工作,但是是否有任何内置函数我不知道吗?
谢谢。
14个回答

281

有一种简单的方法...

$(arr1).not(arr2).length === 0 && $(arr2).not(arr1).length === 0

如果以上返回 true,则无论元素顺序如何,两个数组都是相同的。

注意:仅适用于使用 JSON 对象时的 jQuery 版本 < 3.0.0


12
+1,然而当你将一个包含相同属性的对象与数组进行比较时,例如 [0,1] == {0:0,1:1,length=2},它会返回 true。 - David Hellsing
4
为什么 $(arr1).not(arr2).length == 0 不足够? - Alexxus
10
@Alexxus,你需要使用两个比较操作符,因为not是一个过滤函数,不是一个相等函数。试着用 [1,2][1] 进行实验,在不同的顺序下你将得到 [][2] 两种结果。请记住不要改变原来的意思。 - Noyo
3
请注意,如果数组中有重复项,这将返回true。因此,像 [1,1,2,2,3,3] == [1,2,3] 这样的情况是正确的。 - Philll_t
3
自 jQuery 3.0.0-rc1 起,not 方法不再支持普通对象。请参阅 https://github.com/jquery/jquery/issues/3147。 - Marc-André Lafortune
显示剩余3条评论

36
我今天也在寻找相关信息,找到了这个网站:http://www.breakingpar.com/bkp/home.nsf/0/87256B280015193F87256BFB0077DFFD,不过我不确定它是否是一个好的解决方案,因为他们提到了一些性能考虑。我喜欢jQuery帮助方法的想法。@David 我更希望你的比较方法像这样工作:
jQuery.compare(a, b)

对我来说做以下这些事情没有意义:

$(a).compare(b)

其中a和b是数组。通常,当您使用$(something)时,您会传递一个选择器字符串以与DOM元素一起使用。

关于排序和“缓存”排序后的数组:

  • 我认为,在方法开始时仅对其进行一次排序而不是每次循环都进行排序并不是“缓存”。每次调用compare(b)时,排序仍将发生。那只是语义问题,但是......
  • for (var i = 0; t[i]; i++) { ...如果您的t数组中包含一个false值,则此循环将提前结束,因此$([1, 2, 3, 4]).compare([1, false, 2, 3])返回true
  • 更重要的是,数组sort()方法在原地对数组进行排序,因此执行var b = t.sort() ......不会创建原始数组的排序副本,它对原始数组进行排序,并在中分配了引用。我认为compare方法不应该有副作用。

看来我们需要在操作它们之前先复制数组。我在jQuery中找到的最好的答案是John Resig在这里回答的!在JavaScript中深度克隆对象的最有效方法是什么? (请参见他的答案评论中的数组版本的对象克隆配方)

在这种情况下,我认为它的代码应该是:

jQuery.extend({
    compare: function (arrayA, arrayB) {
        if (arrayA.length != arrayB.length) { return false; }
        // sort modifies original array
        // (which are passed by reference to our method!)
        // so clone the arrays before sorting
        var a = jQuery.extend(true, [], arrayA);
        var b = jQuery.extend(true, [], arrayB);
        a.sort(); 
        b.sort();
        for (var i = 0, l = a.length; i < l; i++) {
            if (a[i] !== b[i]) { 
                return false;
            }
        }
        return true;
    }
});

var a = [1, 2, 3];
var b = [2, 3, 4];
var c = [3, 4, 2];

jQuery.compare(a, b);
// false

jQuery.compare(b, c);
// true

// c is still unsorted [3, 4, 2]

2
实际上,我可能会将这个方法命名为'arrayCompare'而不是'compare',因为它只是为了处理数组而设计的... - Anentropic
确实非常准确。非常感谢。 - dimitarvp

16

我的方法非常不同- 我使用JSON.stringify展开了两个集合,并使用普通字符串比较来检查它们是否相等。

也就是说:

var arr1 = [
             {Col: 'a', Val: 1}, 
             {Col: 'b', Val: 2}, 
             {Col: 'c', Val: 3}
           ];

var arr2 = [
             {Col: 'x', Val: 24}, 
             {Col: 'y', Val: 25}, 
             {Col: 'z', Val: 26}
           ];

if(JSON.stringify(arr1) == JSON.stringify(arr2)){
    alert('Collections are equal');
}else{
    alert('Collections are not equal');
}

注意:请注意,此方法假定两个集合以类似的方式排序,如果不是,则会给出错误结果!


1
我需要一个简单的方法来比较我的单元测试中的数组,确保两个数组具有相同的顺序。非常好用,谢谢。 - aymericbeaumet
谢谢你,你救了我的一天。 - Sourabh Kumar Sharma

14

将两个数组转换为字符串并进行比较

if (JSON.stringify(array1) == JSON.stringify(array2))
{
    // your code here
}

1
似乎适用于比较嵌套数组和有序的情况。 - Pierre de LESPINAY

3

我发现这个讨论是因为我需要一种比较数组和对象的方法。使用这里的示例,我得出了以下结论(为了清晰起见,分成了3个方法):

jQuery.extend({
    compare : function (a,b) {
        var obj_str = '[object Object]',
            arr_str = '[object Array]',
            a_type  = Object.prototype.toString.apply(a),
            b_type  = Object.prototype.toString.apply(b);

            if ( a_type !== b_type) { return false; }
            else if (a_type === obj_str) {
                return $.compareObject(a,b);
            }
            else if (a_type === arr_str) {
                return $.compareArray(a,b);
            }
            return (a === b);
        }
});

jQuery.extend({
    compareArray: function (arrayA, arrayB) {
        var a,b,i,a_type,b_type;
        // References to each other?
        if (arrayA === arrayB) { return true;}

        if (arrayA.length != arrayB.length) { return false; }
        // sort modifies original array
        // (which are passed by reference to our method!)
        // so clone the arrays before sorting
        a = jQuery.extend(true, [], arrayA);
        b = jQuery.extend(true, [], arrayB);
        a.sort(); 
        b.sort();
        for (i = 0, l = a.length; i < l; i+=1) {
            a_type = Object.prototype.toString.apply(a[i]);
            b_type = Object.prototype.toString.apply(b[i]);

            if (a_type !== b_type) {
                return false;
            }

            if ($.compare(a[i],b[i]) === false) {
                return false;
            }
        }
        return true;
    }
});

jQuery.extend({
    compareObject : function(objA,objB) {

        var i,a_type,b_type;

        // Compare if they are references to each other 
        if (objA === objB) { return true;}

        if (Object.keys(objA).length !== Object.keys(objB).length) { return false;}
        for (i in objA) {
            if (objA.hasOwnProperty(i)) {
                if (typeof objB[i] === 'undefined') {
                    return false;
                }
                else {
                    a_type = Object.prototype.toString.apply(objA[i]);
                    b_type = Object.prototype.toString.apply(objB[i]);

                    if (a_type !== b_type) {
                        return false; 
                    }
                }
            }
            if ($.compare(objA[i],objB[i]) === false){
                return false;
            }
        }
        return true;
    }
});

测试

var a={a : {a : 1, b: 2}},
    b={a : {a : 1, b: 2}},
    c={a : {a : 1, b: 3}},
    d=[1,2,3],
    e=[2,1,3];

console.debug('a and b = ' + $.compare(a,b)); // a and b = true
console.debug('b and b = ' + $.compare(b,b)); // b and b = true
console.debug('b and c = ' + $.compare(b,c)); // b and c = false
console.debug('c and d = ' + $.compare(c,d)); // c and d = false
console.debug('d and e = ' + $.compare(d,e)); // d and e = true

3

在我的情况下,比较的数组只包含数字字符串。这个解决方案对我很有效:

function are_arrs_equal(arr1, arr2){
    return arr1.sort().toString() === arr2.sort().toString()
}

让我们来测试一下吧!

arr1 = [1, 2, 3, 'nik']
arr2 = ['nik', 3, 1, 2]
arr3 = [1, 2, 5]

console.log (are_arrs_equal(arr1, arr2)) //true
console.log (are_arrs_equal(arr1, arr3)) //false

这个解决方案对我也起作用了...谢谢 - user3497034

1

如果你只想比较数组的内容,那么有一个有用的jQuery函数$.inArray()

var arr = [11, "String #1", 14, "String #2"];
var arr_true = ["String #1", 14, "String #2", 11]; // contents are the same as arr
var arr_false = ["String #1", 14, "String #2", 16]; // contents differ

function test(arr_1, arr_2) {
    var equal = arr_1.length == arr_2.length; // if array sizes mismatches, then we assume, that they are not equal
    if (equal) {
        $.each(arr_1, function (foo, val) {
            if (!equal) return false;
            if ($.inArray(val, arr_2) == -1) {
                equal = false;
            } else {
                equal = true;
            }
        });
    }
    return equal;
}

alert('Array contents are the same? ' + test(arr, arr_true)); //- returns true
alert('Array contents are the same? ' + test(arr, arr_false)); //- returns false

好的解决方案,但我不确定它是否考虑了具有相同元素但顺序不同的数组。 - Matt
你可以将 if (!equal) return false; 移动到 $.each 的底部,以避免再次触发该函数。并且你可以返回 equal; 以避免比较。 - Matt

1

Sudhakar R的jQuery全局方法中的简单一行代码。

/**
 * Compare two arrays if they are equal even if they have different order.
 *
 * @link https://dev59.com/ZHI-5IYBdhLWcg3wm5lG#7726509
 */
jQuery.extend({
  /**
   * @param {array} a
   *   First array to compare.
   * @param {array} b
   *   Second array to compare.
   * @return {boolean}
   *   True if both arrays are equal, otherwise false.
   */
  arrayCompare: function (a, b) {
    return $(a).not(b).get().length === 0 && $(b).not(a).get().length === 0;
  }
});

1

将数组转换为字符串并进行比较

var arr = [1,2,3], 
arr2 = [1,2,3]; 
console.log(arr.toString() === arr2.toString());

1

我认为没有一个好的“jQuery”方法来做到这一点,但如果你需要效率,可以通过某个键(唯一对象字段之一)映射其中一个数组,然后通过循环遍历另一个数组并与刚刚构建的映射或关联数组进行比较。

如果效率不是问题,只需将A中的每个对象与B中的每个对象进行比较。只要|A|和|B|很小,你应该没问题。


@Stefan,感谢您的快速回复。您能发布一些关于您映射想法的示例代码吗?谢谢。 - Matt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接