Javascript nesnelerinin iki dizisini karşılaştırmak için jQuery kullanma


93

Aynı olup olmadıklarını görmek için karşılaştırmak istediğim iki JavaScript Nesnesi dizisi var. Nesneler her dizide aynı sırada olmayabilir (ve büyük olasılıkla olmayacaktır). Her dizide 10'dan fazla nesne olmamalıdır. JQuery'nin bu soruna zarif bir çözümü olabileceğini düşündüm, ancak çevrimiçi olarak fazla bir şey bulamadım.

Kaba yuvalanmış bir $.each(array, function(){})çözümün işe yarayabileceğini biliyorum , ancak farkında olmadığım herhangi bir yerleşik işlev var mı?

Teşekkürler.

Yanıtlar:


278

Kolay bir yol var ...

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

Yukarıdakiler true döndürürse, öğeler farklı sırada olsa bile her iki dizi de aynıdır.

NOT: Bu, JSON nesnelerini kullanırken yalnızca jquery sürümleri <3.0.0 için çalışır


12
+1, ancak bir Dizi ile aynı özellikleri içeren bir Nesneyi karşılaştırdığınızda doğruya eşittir, f.ex[0,1] == {0:0,1:1,length=2}
David Hellsing

4
neden $(arr1).not(arr2).length == 0yeterli değil
Alexxus

10
@Alexxus, her iki karşılaştırmaya da ihtiyacınız var çünkü notbir eşitlik işlevi değil, bir filtre işlevi. İle deneyin [1,2]ve [1]. Bir siparişte alırsınız []ve diğerinde alırsınız [2].
Noyo

3
Bir dizide kopyalarınız varsa, bunun true olacağını unutmayın. Yani şöyle bir şey: "[1,1,2,2,3,3] == [1,2,3]" doğrudur.
Philll_t

3
jQuery not, 3.0.0-rc1'den itibaren artık genel nesnelerle çalışmamaktadır. Bkz. Github.com/jquery/jquery/issues/3147
Marc-André Lafortune

35

Ben de bugün bunu arıyordum ve buldum: http://www.breakingpar.com/bkp/home.nsf/0/87256B280015193F87256BFB0077DFFD

Bunun iyi bir çözüm olup olmadığını bilmiyorum, ancak dikkate alınan bazı performans hususlarından bahsediyorlar.

Bir jQuery yardımcı yöntemi fikrini beğendim. @David Karşılaştırma yönteminizin şöyle çalışmasını tercih ederim:

jQuery.compare(a, b)

Yapmam bana mantıklı gelmiyor:

$(a).compare(b)

a ve b dizilerdir. Normalde $ (bir şey) yaptığınızda, DOM öğeleriyle çalışmak için bir seçici dizge geçiriyor olursunuz.

Ayrıca sıralanan dizilerin sıralanması ve 'önbelleğe alınması' ile ilgili olarak:

  • Döngünün her defasında değil, yöntemin başında bir kez sıralamanın 'önbelleğe alma' olduğunu düşünmüyorum. Karşılaştırma (b) 'yi her çağırdığınızda sıralama yine de gerçekleşecektir. Bu sadece anlambilim, ama ...
  • for (var i = 0; t [i]; i ++) { ... t diziniz bir yerde yanlış bir değer içeriyorsa bu döngü erken biter , yani $ ([1, 2, 3, 4]). karşılaştır ( [1, false, 2, 3]) true değerini döndürür !
  • Daha da önemlisi dizi sıralama () metodu diziyi sıralar yerde bunu yaparken, = t.sort () b var o sıralar orijinal dizinin sıralanmış bir kopyasını yaratmaz ... orijinal diziyi ve aynı zamanda bir atar başvuru için içeri b . Karşılaştırma yönteminin yan etkileri olması gerektiğini düşünmüyorum.

Görünüşe göre yapmamız gereken şey dizileri üzerinde çalışmadan önce kopyalamak. Bunu jQuery yoluyla nasıl yapacağıma dair bulabildiğim en iyi cevap SO'da John Resig'den başkası değildi! JavaScript'te bir nesneyi derinlemesine klonlamanın en etkili yolu nedir? (nesne klonlama tarifinin dizi versiyonu için cevabındaki yorumlara bakınız)

Bu durumda kodun şöyle olacağını düşünüyorum:

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
Aslında muhtemelen bu yönteme 'karşılaştırma' yerine 'arrayCompare' adını verirdim çünkü üzerinde çalışmak için tasarlanmış tek şey bu ...
Anentropic

Gerçekten nokta. Çok teşekkürler.
dimitarvp

14

Yaklaşımım oldukça farklıydı - JSON.stringify kullanarak her iki koleksiyonu da düzleştirdim ve eşitliği kontrol etmek için normal bir dize karşılaştırması kullandım.

Yani

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

Not: Lütfen metodunun her iki Koleksiyonun da benzer şekilde sıralandığını varsaydığını, aksi takdirde size yanlış bir sonuç vereceğini unutmayın!


1
Birim testlerimde dizileri karşılaştırmak için basit bir yönteme ihtiyacım vardı ve iki dizi için aynı sırayı sağladım. Çok güzel teşekkürler
aymericbeaumet

Teşekkürler, günümü kurtardın
Sourabh Kumar Sharma

12

Her iki diziyi dizeye dönüştür ve karşılaştır

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

1
İç içe dizileri karşılaştırmak ve sıranın önemli olduğu zamanlar için iyi görünüyor.
Pierre de LESPINAY

3

Bu tartışmayı buldum çünkü dizileri ve nesneleri derinlemesine karşılaştırmak için bir yola ihtiyacım vardı. Buradaki örnekleri kullanarak aşağıdakileri buldum (netlik için 3 yönteme ayrılmış):

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

Test yapmak

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

Benim durumumda karşılaştırılan diziler yalnızca sayıları ve dizeleri içerir . Bu çözüm benim için çalıştı:

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

Hadi deneyelim!

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

1

Bunu yapmanın iyi bir "jQuery" yolu olduğunu sanmıyorum, ancak verimliliğe ihtiyacınız varsa, dizilerden birini belirli bir anahtarla (benzersiz nesne alanlarından biri) eşleyin ve ardından diğer dizide döngü yaparak karşılaştırma yapın ve yeni oluşturduğunuz harita veya ilişkilendirilebilir diziyle karşılaştırarak.

Verimlilik sorun değilse, A'daki her nesneyi B'deki her nesneyle karşılaştırın. | A | ve | B | küçük, iyi olmalısın.


@Stefan, hızlı yanıt için teşekkürler. Haritalama fikriniz için örnek kod gönderebilir misiniz? Teşekkürler.
MegaMatt

1

Peki, sadece dizilerin içeriğini karşılaştırmak istiyorsanız, kullanışlı bir jQuery işlevi var $ .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

İyi çözüm, ancak bunun aynı öğelere sahip dizileri farklı bir sırayla hesaba kattığından emin değilim.
MegaMatt

(! Eşit) yanlış döndürürse hareket edebilirsiniz; işlevi tekrar çalıştırmamak için $ .each'in altına kadar. Ve eşit olarak dönebilirsiniz; bir karşılaştırmayı önlemek için.
Matt

1

Diziyi dizeye değiştirin ve karşılaştırın

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

1

Sudhakar R'den jQuery global yöntemi olarak güzel bir astar .

/**
 * 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;
  }
});

0

Bunu jQuery ile bazı dizi karşılaştırmaları yaparken de buldum. Benim durumumda diziler olduğunu bildiğim dizelerim vardı:

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

Ama bunun tam bir eşleşme mi yoksa sadece kısmi bir eşleşme mi olduğunu önemsiyordum, bu yüzden Sudhakar R'nin cevabına dayanarak aşağıdakine benzer bir şey kullandım:

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

0

Yinelenenler [1, 1, 2]eşit [2, 1]olmamalı ancak eşit olması gereken önemliyse [1, 2, 1], işte bir referans sayma çözümü:

  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()}

İşte oynanacak keman .


0

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>


-3

Bunu dene

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

Bu hem a hem de b'yi değiştirir ve yalnızca ilk öğeyi karşılaştırır. o ne lan.
ScottJ

1
@ScottJ Mr.AH Soru iki diziyi karşılaştırmaktır .. Her iki dizi de eşitse sıralandıktan sonra a [0] == b [0]. wtf you bah.
istisna

2
Korkarım AH'nin ne anlama geldiğini bilmiyorum ve google yardımcı olmadı. Ama yorumum bu kadar yanlışsa, bu kod neden 21 Şubat'ta tamamen yeniden yazıldı?
ScottJ

@ScottJ Büyük olasılıkla AH === wtf
İstisna
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.