简体   繁体   English

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

[英]Using jQuery to compare two arrays of Javascript objects

I have two arrays of JavaScript Objects that I'd like to compare to see if they are the same. 我有两个JavaScript对象数组,我想比较它们是否相同。 The objects may not (and most likely will not) be in the same order in each array. 对象可能不会(并且很可能不会)在每个数组中具有相同的顺序。 Each array shouldn't have any more than 10 objects. 每个数组不应超过10个对象。 I thought jQuery might have an elegant solution to this problem, but I wasn't able to find much online. 我认为jQuery可能有一个优雅的解决方案来解决这个问题,但我无法在网上找到太多。

I know that a brute nested $.each(array, function(){}) solution could work, but is there any built in function that I'm not aware of? 我知道一个粗暴的嵌套$.each(array, function(){})解决方案可以工作,但有没有我不知道的内置函数?

Thanks. 谢谢。

There is an easy way... 有一个简单的方法......

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

If the above returns true, both the arrays are same even if the elements are in different order. 如果以上返回true,则即使元素的顺序不同,两个数组也是相同的。

NOTE: This works only for jquery versions < 3.0.0 when using JSON objects 注意:这仅适用于使用JSON对象时jquery版本<3.0.0

I was also looking for this today and found: http://www.breakingpar.com/bkp/home.nsf/0/87256B280015193F87256BFB0077DFFD 我今天也在寻找这个并找到: http//www.breakingpar.com/bkp/home.nsf/0/87256B280015193F87256BFB0077DFFD

Don't know if that's a good solution though they do mention some performance considerations taken into account. 不知道这是否是一个很好的解决方案,尽管他们确实提到了一些考虑的性能因素。

I like the idea of a jQuery helper method. 我喜欢jQuery帮助器方法的想法。 @David I'd rather see your compare method to work like: @David我宁愿看你的比较方法如下:

jQuery.compare(a, b)

I doesn't make sense to me to be doing: 我对自己没有意义:

$(a).compare(b)

where a and b are arrays. 其中a和b是数组。 Normally when you $(something) you'd be passing a selector string to work with DOM elements. 通常当你$(某事物)时,你会传递一个选择器字符串来处理DOM元素。

Also regarding sorting and 'caching' the sorted arrays: 还有关排序和“缓存”排序数组:

  • I don't think sorting once at the start of the method instead of every time through the loop is 'caching'. 我不认为在方法开始时排序一次而不是每次循环都是“缓存”。 The sort will still happen every time you call compare(b). 每次调用compare(b)时仍会发生排序。 That's just semantics, but... 那只是语义,但......
  • for (var i = 0; t[i]; i++) { ...this loop finishes early if your t array contains a false value in it somewhere, so $([1, 2, 3, 4]).compare([1, false, 2, 3]) returns true ! for(var i = 0; t [i]; i ++){ ...如果你的t数组在某处包含一个假值,那么这个循环会提前结束,所以$([1,2,3,4])。compare( [1,false,2,3]返回true
  • More importantly the array sort() method sorts the array in place , so doing var b = t.sort() ...doesn't create a sorted copy of the original array, it sorts the original array and also assigns a reference to it in b . 更重要的是阵列sort()方法排序到位阵列,这样算下来变种B = t.sort()......不创建原始数组的排序副本,它按原始数组,并分配给一个参考它在b I don't think the compare method should have side-effects. 我不认为比较方法应该有副作用。

It seems what we need to do is to copy the arrays before working on them. 我们需要做的是在处理数组之前复制数组。 The best answer I could find for how to do that in a jQuery way was by none other than John Resig here on SO! 对于如何以jQuery方式执行此操作,我能找到的最佳答案是John Resig在这里! What is the most efficient way to deep clone an object in JavaScript? 在JavaScript中深度克隆对象的最有效方法是什么? (see comments on his answer for the array version of the object cloning recipe) (请参阅有关对象克隆配方的数组版本的答案的评论)

In which case I think the code for it would be: 在这种情况下,我认为它的代码是:

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]

My approach was quite different - I flattened out both collections using JSON.stringify and used a normal string compare to check for equality. 我的方法完全不同 - 我使用JSON.stringify将两个集合展平,并使用普通的字符串比较来检查是否相等。

Ie

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');
}

NB: Please note that his method assumes that both Collections are sorted in a similar fashion, if not, it would give you a false result! 注意:请注意,他的方法假定两个集合都以类似的方式排序,如果没有,它会给你一个错误的结果!

Convert both array to string and compare 将两个数组转换为字符串并进行比较

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

I found this discussion because I needed a way to deep compare arrays and objects. 我找到了这个讨论,因为我需要一种深入比较数组和对象的方法。 Using the examples here, I came up with the following (broken up into 3 methods for clarity): 使用这里的示例,我想出了以下内容(为了清晰起见分为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;
    }
});

Testing 测试

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

In my case compared arrays contain only numbers and strings . 在我的情况下,比较数组只包含数字字符串 This solution worked for me: 这个解决方案对我有用:

function are_arrs_equal(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_equal(arr1, arr2)) //true
console.log (are_arrs_equal(arr1, arr3)) //false

The nice one liner from Sudhakar R as jQuery global method. 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;
  }
});

I don't think there's a good "jQuery " way to do this, but if you need efficiency, map one of the arrays by a certain key (one of the unique object fields), and then do comparison by looping through the other array and comparing against the map, or associative array, you just built. 我不认为有一个很好的“jQuery”方法可以做到这一点,但是如果你需要效率,可以通过某个键(一个唯一的对象字段)映射其中一个数组,然后通过循环遍历另一个数组进行比较和你刚刚建立的地图或关联数组进行比较。

If efficiency is not an issue, just compare every object in A to every object in B. As long as |A| 如果效率不是问题,只需将A中的每个对象与B中的每个对象进行比较。只要| A | and |B| 和| B | are small, you should be okay. 很小,你应该没事。

Well, if you want to compare only the contents of arrays, there's a useful jQuery function $.inArray() 好吧,如果你只想比较数组的内容,那么有一个有用的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

Change array to string and compare 将数组更改为字符串并进行比较

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

I also found this when looking to do some array comparisons with jQuery. 我在寻找与jQuery进行一些数组比较时也发现了这一点。 In my case I had strings which I knew to be arrays: 在我的情况下,我有字符串,我知道是数组:

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

But I cared if it was a complete match or only a partial match, so I used something like the following, based off of Sudhakar R's answer: 但我关心的是它是完全匹配还是只是部分匹配,所以我根据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';
  }
}

If duplicates matter such that [1, 1, 2] should not be equal to [2, 1] but should equal [1, 2, 1] , here is a reference counting solution: 如果重复事项使得[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 . 这是小提琴

 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 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.js"></script> 

Try this 试试这个

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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM