【问题标题】:Using jQuery to compare two arrays of Javascript objects使用 jQuery 比较两个 Javascript 对象数组
【发布时间】:2010-12-18 21:17:40
【问题描述】:

我有两个 JavaScript 对象数组,我想比较它们是否相同。对象可能不会(也很可能不会)在每个数组中的顺序相同。每个数组不应有超过 10 个对象。我认为 jQuery 可能有一个优雅的解决方案来解决这个问题,但我无法在网上找到很多。

我知道粗略的嵌套 $.each(array, function(){}) 解决方案可以工作,但有没有我不知道的内置函数?

谢谢。

【问题讨论】:

    标签: javascript jquery arrays object compare


    【解决方案1】:

    有一个简单的方法...

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

    如果以上返回true,即使元素的顺序不同,两个数组也是相同的。

    注意:这仅适用于使用 JSON 对象时

    【讨论】:

    • +1,但是当您将数组与包含相同属性的对象进行比较时,它等于 true,f.ex [0,1] == {0:0,1:1,length=2}
    • 为什么$(arr1).not(arr2).length == 0不够用?
    • @Alexxus,你需要两个比较,因为not 是一个过滤函数,而不是一个相等函数。试试[1,2][1]。在一个订单中,您将获得[],在另一个订单中,您将获得[2]
    • 请注意,如果数组中有重复项,这将返回 true。所以类似:` [1,1,2,2,3,3] == [1,2,3]` 是真的。
    • jQuery not 自 3.0.0-rc1 起不再适用于通用对象。见github.com/jquery/jquery/issues/3147
    【解决方案2】:

    我今天也在找这个,发现: 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 数组在某处包含错误值,则此循环会提前结束,所以 $([1, 2, 3, 4]).compare([1, false, 2, 3]) 返回 true!
    • 更重要的是,数组 sort() 方法对数组进行就地排序,因此 var b = t.sort() ...不会创建已排序的原始数组的副本,它对 original 数组进行排序,并在 b 中为其分配 reference。我不认为 compare 方法应该有副作用。

    看来我们需要做的是在处理数组之前复制数组。我能找到的关于如何以 jQuery 方式做到这一点的最佳答案就是 John Resig 在这里! What is the most efficient way to deep clone an object in JavaScript? (有关对象克隆配方的数组版本的答案,请参见 cmets)

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

    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]
    

    【讨论】:

    • 实际上我可能会将此方法命名为“arrayCompare”而不是“compare”,因为这是它唯一设计用于处理的东西......
    • 确实准确。非常感谢。
    【解决方案3】:

    我的方法完全不同 - 我使用 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');
    }
    

    注意:请注意,他的方法假设两个集合都以相似的方式排序,如果不是,它会给你一个错误的结果!

    【讨论】:

    • 我需要一个简单的方法来比较单元测试中的数组,确保两个数组的顺序相同。非常好,谢谢。
    • 谢谢你拯救了我的一天
    【解决方案4】:

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

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

    【讨论】:

    • 似乎很适合比较嵌套数组以及顺序很重要的情况。
    【解决方案5】:

    我找到了这个讨论,因为我需要一种方法来深入比较数组和对象。使用此处的示例,我想出了以下内容(为清楚起见,分为 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
    

    【讨论】:

      【解决方案6】:

      在我的例子中,比较数组只包含 numbersstrings。这个解决方案对我有用:

      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
      

      【讨论】:

        【解决方案7】:

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

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

        【讨论】:

        • @Stefan,感谢您的快速回复。您可以为您的映射想法发布示例代码吗?谢谢。
        【解决方案8】:

        好吧,如果你只想比较数组的内容,有一个有用的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
        

        【讨论】:

        • 很好的解决方案,但我不确定这是否考虑了具有相同元素但顺序不同的数组。
        • 你可以移动 if (!equal) return false;一直到 $.each 的底部,以避免再次触发该函数。你可以返回相等;避免比较。
        【解决方案9】:

        将数组更改为字符串并进行比较

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

        【讨论】:

          【解决方案10】:

          来自Sudhakar R 的漂亮的 jQuery 全局方法。

          /**
           * Compare two arrays if they are equal even if they have different order.
           *
           * @link https://stackoverflow.com/a/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;
            }
          });
          

          【讨论】:

            【解决方案11】:

            我在使用 jQuery 进行一些数组比较时也发现了这一点。就我而言,我有字符串,我知道它们是数组:

            var needle = 'apple orange';
            var haystack = 'kiwi orange banana apple plum';
            

            但我关心它是完全匹配还是部分匹配,所以我根据 Sudhakar R 的回答使用了以下内容:

            function compareStrings( needle, haystack ){
              var needleArr = needle.split(" "),
                haystackArr = haystack.split(" "),
                compare = $(haystackArr).not(needleArr).get().length;
            
              if( compare == 0 ){
                return 'all';
              } else if ( compare == haystackArr.length  ) {
                return 'none';
              } else {
                return 'partial';
              }
            }
            

            【讨论】:

              【解决方案12】:

              如果重复很重要,以至于 [1, 1, 2] 不应该等于 [2, 1] 但应该等于 [1, 2, 1],这里有一个引用计数解决方案:

                const arrayContentsEqual = (arrayA, arrayB) => {
                  if (arrayA.length !== arrayB.length) {
                    return false}
              
                  const refCount = (function() {
                    const refCountMap = {};
                    const refCountFn = (elt, count) => {
                        refCountMap[elt] = (refCountMap[elt] || 0) + count}
                    refCountFn.isZero = () => {
                      for (let elt in refCountMap) {
                        if (refCountMap[elt] !== 0) {
                          return false}}
                      return true}
                    return refCountFn})()
              
                  arrayB.map(eltB => refCount(eltB, 1));
                  arrayA.map(eltA => refCount(eltA, -1));
                  return refCount.isZero()}
              

              Here is the fiddle to play with.

              【讨论】:

                【解决方案13】:

                var arr1 = [
                             {name: 'a', Val: 1}, 
                             {name: 'b', Val: 2}, 
                             {name: 'c', Val: 3}
                           ];
                
                var arr2 = [
                             {name: 'c', Val: 3},
                             {name: 'x', Val: 4}, 
                             {name: 'y', Val: 5}, 
                             {name: 'z', Val: 6}
                           ];
                var _isEqual = _.intersectionWith(arr1, arr2, _.isEqual);// common in both array
                var _difference1 = _.differenceWith(arr1, arr2, _.isEqual);//difference from array1 
                var _difference2 = _.differenceWith(arr2, arr1, _.isEqual);//difference from array2 
                console.log(_isEqual);// common in both array
                console.log(_difference1);//difference from array1 
                console.log(_difference2);//difference from array2 
                &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.js"&gt;&lt;/script&gt;

                【讨论】:

                  【解决方案14】:

                  试试这个

                  function check(c,d){
                    var a = c, b = d,flg = 0;
                    if(a.length == b.length) 
                    { 
                       for(var i=0;i<a.length;i++) 
                             a[i] != b[i] ? flg++ : 0; 
                    } 
                    else  
                    { 
                       flg = 1; 
                    } 
                    return flg = 0;
                  }
                  

                  【讨论】:

                  • 修改a和b,只比较第一个元素。 wtf.
                  • @ScottJ Mr.AH 问题是比较两个数组。排序后两个数组是否相等 a[0] == b[0]。 wtf你呸。
                  • 恐怕我不知道AH是什么意思,谷歌也没有帮助。但如果我的评论如此离题,为什么这段代码在 2 月 21 日完全重写?
                  • @ScottJ 很可能啊 === wtf
                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2019-08-02
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2019-06-09
                  相关资源
                  最近更新 更多