JavaScript'te diziler nasıl karşılaştırılır?


988

İki diziyi karşılaştırmak istiyorum ... ideal, verimli. Hiçbir şey fantezi, sadece trueaynı ve falsedeğilse. Şaşırtıcı olmayan bir şekilde, karşılaştırma operatörü çalışmıyor gibi görünüyor.

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

Her diziyi kodlayan JSON yapar, ancak her değeri yinelemek zorunda kalmadan dizileri karşılaştırmanın daha hızlı veya "daha iyi" bir yolu var mı?


5
Önce uzunluklarını ve her bir değere eşit olup olmadığını karşılaştırabilirsiniz.
TJHeuvel

55
İki diziyi sizin için eşit yapan nedir? Aynı unsurlar? Aynı eleman sırası? JSON olarak kodlama yalnızca dizinin öğesi JSON'a serileştirilebildiği sürece çalışır. Dizi nesneler içeriyorsa ne kadar derine inersiniz? İki nesne ne zaman "eşittir"?
Felix Kling

48
@FelixKling, "eşitliği" tanımlamak kesinlikle ince bir konudur, ancak üst düzey dillerden JavaScript'e gelen insanlar için, benzerlik için bir mazeret yoktur ([] == []) == false.
Alex D

4
@AlexD, dizilerin beklediğiniz gibi referans eşitliğini kullandığına benziyor. Bunu yapamazsan çok korkunç olurdu
JonnyRaa

3
@AlexD Bunun gerçekleşmediği bir dili düşünemiyorum. C ++ 'da iki işaretçi karşılaştırırsınız - false. Java'da javascript'tekiyle aynı şeyi yapıyorsunuz. PHP'de, perde arkasında bir şey diziler arasında dolaşır - PHP'ye daha yüksek bir dil mi diyorsunuz?
Tomáš Zato - Monica'yı yeniden başlat

Yanıtlar:


877

Dizileri karşılaştırmak için, bunları döngüye sokun ve her değeri karşılaştırın:

Dizileri karşılaştırma:

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

Kullanımı:

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

" Ama dizeleri karşılaştırmak çok daha hızlı - döngüler yok ... " diyebilirsiniz , o zaman orada döngüler olduğunu not etmelisiniz. Diziyi dizeye dönüştüren ilk özyinelemeli ve ikinci dizeyi karşılaştıran ikinci özyinelemeli döngü. Yani bu yöntem dize kullanımından daha hızlıdır .

Daha büyük miktarlarda verinin her zaman dizilerde saklanması gerektiğine inanıyorum. Ancak nesneleri kullanırsanız, bunlar da kısmen karşılaştırılabilir.
Bunu nasıl yapacağınız aşağıda açıklanmıştır:

Nesneleri karşılaştırma:

Yukarıda, şu anda aynı verileri içeriyor olsalar bile , iki nesne örneğinin asla eşit olmayacağını belirtmiştim:

({a:1, foo:"bar", numberOfTheBeast: 666}) == ({a:1, foo:"bar", numberOfTheBeast: 666})  //false

Bunun bir nedeni vardır, çünkü nesneler içinde özel değişkenler olabilir .

Ancak, yalnızca veri içermek için nesne yapısını kullanırsanız karşılaştırma hala mümkündür:

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

Bununla birlikte, bunun sınıf örnekleri ve diğer şeyleri değil, JSON benzeri verileri karşılaştırmada hizmet etmek olduğunu unutmayın. Daha karmaşık nesneleri karşılaştırmak istiyorsanız, bu cevaba bakın ve süper uzun fonksiyon .
Bu özelliği kullanabilmek Array.equalsiçin orijinal işlevi biraz düzenlemelisiniz:

...
    // 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]) {
...

Her iki işlev için de küçük bir test aracı yaptım .

Bonus: indexOfve ile iç içe dizilercontains

Samy Bencherif, burada bulunan iç içe dizilerde belirli bir nesneyi aradığınız durum için yararlı işlevler hazırladı : https://jsfiddle.net/SamyBencherif/8352y6yw/


27
Sıkı karşılaştırmalar yapmak istiyorsanız this[i] !== array[i]yerine kullanın !=.
Tim S.15

38
equalsBunun yerine yönteminiz çağrılmalıdır compare. En azından .NET'te, karşılaştırma genellikle hangi nesnenin diğerinden daha büyük olduğunu gösteren işaretli bir int döndürür. Bkz: Comparer.Compare .
Oliver

15
Sadece bunu yapmanın doğru yolu değil, aynı zamanda çok daha etkilidir. İşte bu soruda önerilen tüm yöntemler için hazırladığım hızlı bir jsperf betiği. jsperf.com/comparing-arrays2
Tolga E

96
Yerleşik bir türün prototipini değiştirmek kesinlikle doğru bir yol
Jasper

31
Ayrıca, yeniden yazmanın kolay olup olmadığı değil, bir cevabın kötü uygulama olarak kabul edilen bir şeyi ( geliştirici.mozilla.org/ en-US/docs/Web/JavaScript/Guide/…) önermemesi ve kesinlikle "Doğru yol" başlığının altında bunu yapmayın
Jasper

386

Bu sadece skaler diziler için geçerli olsa da (aşağıdaki nota bakın), kısadır:

array1.length === array2.length && array1.every(function(value, index) { return value === array2[index]})

Rr, ECMAScript 6 / Ok İşlevli CoffeeScript / TypeScript'te:

array1.length === array2.length && array1.every((value, index) => value === array2[index])

(Not: Burada 'skaler', doğrudan kullanılarak karşılaştırılabilecek değerler anlamına gelir ===. Yani: sayılar, dizeler, referans olarak nesneler, referans işlevleri. Karşılaştırma işleçleri hakkında daha fazla bilgi için MDN referansına bakın ).

GÜNCELLEME

Yorumlardan ne okuduğumdan, diziyi sıralamak ve karşılaştırmak doğru sonuç verebilir:

array1.length === array2.length && array1.sort().every(function(value, index) { return value === array2.sort()[index]});

Örneğin:

array1 = [2,3,1,4];
array2 = [1,2,3,4];

Sonra yukarıdaki kod true


19
Her ne kadar okuyucular bunun sıralı dizilerde çalıştığının farkında olmalıdır.
Ellen Spertus

13
@Espertus
Michał Miszczyszyn

36
Evet kesinlikle. Bu fonksiyonun iki diziyi karşılaştırması gerekiyor, bunların sıralanıp sıralanmaması önemli değil, ardışık elemanlarının eşit olması gerekiyor.
Michał Miszczyszyn

22
@espertus Gerçekten de, elemanların her iki dizide de tam olarak aynı sıraya sahip olmaması durumunda doğru dönmeyecektir. Ancak, eşitlik kontrolünün amacı aynı öğeleri içerip içermediklerini kontrol etmek değil, aynı siparişlerde aynı elemente sahip olup olmadıklarını kontrol etmektir.
Quentin Roy

7
Her iki dizinin de aynı sıralanmamış öğeleri içeren (ancak birden çok kez kullanılmayan) eşdeğer olup olmadığını kontrol etmek istiyorsanız, şunları kullanabilirsiniz a1.length==a2.length && a1.every((v,i)=>a2.includes(v)): var a1 =[1,2,3], a2 = [3,2,1];( var a1 =[1,3,3], a2 = [1,1,3];beklendiği gibi çalışmaz)
15'te

208

Dizi / nesne ağır kodlama projeleri için Alt Çizgi kütüphanesini kullanmayı seviyorum ... Alt dizeleri veya Lodash'da, dizileri veya nesneleri şu şekilde karşılaştırıyor olun:

_.isEqual(array1, array2)   // returns a boolean
_.isEqual(object1, object2) // returns a boolean

22
Siparişin önemli olduğuna dikkat edin _.isEqual([1,2,3], [2,1,3]) => false
Vitaliy Alekask

3
ya da sadece isEqualişlevselliği istiyorsanız, her zaman lodash.isequal modülünü kullanabilirsiniz
hellatan

6
Belki _.difference (); sipariş sizin için önemli değilse
Ronan Quillevere

5
Siparişin önemi yoksa diziyi bu kontrolden önce sıralayabiliriz_.isEqual([1,2,3].sort(), [2,1,3].sort()) => true
Filype

en özlü ve açık cevap IMHO :-)
Kieran Ryan

121

Bu bence JSON stringify kullanarak yapmanın en basit yoludur ve bazı durumlarda en iyi çözüm olabilir:

JSON.stringify(a1) === JSON.stringify(a2);

Bu, nesneleri a1ve a2dizelere dönüştürülerek karşılaştırılabilir. Sıralama çoğu durumda önemlidir, çünkü yukarıdaki cevaplardan birinde gösterilen bir sıralama algoritması kullanarak nesneyi sıralayabilir.

Lütfen artık nesneyi değil, nesnenin dize olarak temsilini karşılaştırdığınıza dikkat edin. Tam olarak istediğiniz şey olmayabilir.


iyi cevap ama neden [] == [] yanlış döndürüyor? ikisi de basit nesneler neden?
Pardeep Jain

4
@PardeepJain, bunun nedeni, varsayılan olarak, ECMAScript for Objects içindeki eşitlik operatörünün aynı bellek konumuna başvurduklarında true değerini döndürmesidir. Var x = y = []; // şimdi eşitlik doğrudur.
radtek

7
sadece JSON stringify işlevinin hızlı olmadığını unutmayın. Daha büyük dizilerle kullanıldığında kesinlikle gecikme yaşanacaktır.
Lukas Liesis

6
Soru özellikle JSON.stringify kullanmaktan daha iyi / daha hızlı bir yol olup olmadığını soruyor .
Don Hatch

Bunun neden bazı durumlar için iyi bir çözüm olabileceği konusunda daha ayrıntılı olarak ele alınmaktadır.
radtek

61

"Özdeş" derken ne demek istediğiniz belli değil. Örneğin, diziler ave baltı aynı mıdır (iç içe dizilere dikkat edin)?

var a = ["foo", ["bar"]], b = ["foo", ["bar"]];

Burada, sıkı bir eşitlik kullanarak sırayla her dizinin karşılık gelen öğelerini karşılaştıran ve diziler olan dizi öğelerinin özyinelemeli karşılaştırmasını yapmayan, yukarıdaki örnek için arraysIdentical(a, b)döneceği anlamına gelen optimize edilmiş bir dizi karşılaştırma işlevi false. Genel durumda çalışır, JSON ve join()tabanlı çözümler şunları yapmayacaktır:

function arraysIdentical(a, b) {
    var i = a.length;
    if (i != b.length) return false;
    while (i--) {
        if (a[i] !== b[i]) return false;
    }
    return true;
};

@ASDF: "Özdeş" in ne anlama geldiği belirsiz. Açıkçası bu cevap sadece sığ bir kontrol yapıyor. Bir not ekleyeceğim.
Tim Down

bu, diziler için başarısız olur ([1, 2, [3, 2]], [1, 2, [3, 2]]);
Gopinath Shiva

4
@GopinathShiva: Sadece geri dönmesini beklerseniz başarısız olur true. Cevap, olmayacağını açıklıyor. İç içe dizileri karşılaştırmanız gerekiyorsa, kolayca yinelemeli bir denetim ekleyebilirsiniz.
Tim Down

59

Pratik Yol

"Yanlış" bir çözümün aksine, yalnızca "doğru" ("doğru") ise belirli bir uygulamanın "Doğru Yol ™" olduğunu söylemek yanlış olur. Tomáš'ın çözümü dize tabanlı dizi karşılaştırmasına göre net bir gelişmedir, ancak bu objektif olarak "doğru" anlamına gelmez. Neyse doğru olan nedir ? En hızlı mı? En esnek mi? Anlaması en kolay şey mi? Hata ayıklamak en hızlı mı? En az işlemi kullanıyor mu? Herhangi bir yan etkisi var mı? Hiçbir çözüm her şeyin en iyisini yapamaz.

Tomáš çözümünün hızlı olduğunu söyleyebilirdi ama bunun gereksiz derecede karmaşık olduğunu da söyleyebilirim. Yuvalanmış olsun olmasın tüm diziler için çalışan hepsi bir arada bir çözüm olmaya çalışır. Aslında, girdi olarak sadece dizilerden daha fazlasını kabul eder ve yine de "geçerli" bir cevap vermeye çalışır.


Jenerikler yeniden kullanılabilirlik sunar

Cevabım soruna farklı yaklaşacak. arrayCompareSadece dizilerden adım atmakla ilgili genel bir prosedürle başlayacağım . Oradan, gibi diğer temel karşılaştırma fonksiyonları inşa edeceğiz arrayEqualve arrayDeepEqualvb

// arrayCompare :: (a -> a -> Bool) -> [a] -> [a] -> Bool
const arrayCompare = f => ([x,...xs]) => ([y,...ys]) =>
  x === undefined && y === undefined
    ? true
    : Boolean (f (x) (y)) && arrayCompare (f) (xs) (ys)

Kanımca, en iyi kod türünün yorumlara bile ihtiyacı yoktur ve bu bir istisna değildir. Burada o kadar az şey var ki, bu prosedürün davranışını neredeyse hiç çaba harcamadan anlayabilirsiniz. Elbette, bazı ES6 sözdizimi size yabancı gelebilir, ancak bunun nedeni yalnızca ES6'nın nispeten yeni olmasıdır.

Türün de belirttiği gibi arrayCompare, karşılaştırma işlevini fve iki giriş dizisini alır xsve ys. Çoğunlukla, tek yaptığımız f (x) (y)girdi dizilerindeki her eleman için çağırmaktır . falseKullanıcı tanımlı kısa devre değerlendirmesi sayesinde , kullanıcı tanımlı bir şekilde fgeri gelirse erken dönüyoruz. Yani evet, bu, karşılaştırıcının yinelemeyi erken durdurabileceği ve gereksiz olduğunda giriş dizisinin geri kalanında döngüyü önleyebileceği anlamına gelir.false&&


Sıkı karşılaştırma

Daha sonra, arrayComparefonksiyonumuzu kullanarak , ihtiyaç duyabileceğimiz diğer fonksiyonları kolayca oluşturabiliriz. İlkokulla başlayacağız arrayEqual

// equal :: a -> a -> Bool
const equal = x => y =>
  x === y // notice: triple equal

// arrayEqual :: [a] -> [a] -> Bool
const arrayEqual =
  arrayCompare (equal)

const xs = [1,2,3]
const ys = [1,2,3]
console.log (arrayEqual (xs) (ys))      //=> true
// (1 === 1) && (2 === 2) && (3 === 3)  //=> true

const zs = ['1','2','3']
console.log (arrayEqual (xs) (zs))      //=> false
// (1 === '1')                          //=> false

Bu kadar basit. arrayEqualile tanımlanabilir arrayCompareile karşılaştıran bir karşılaştırma fonksiyonu ve aetmek bkullanılarak ===(katı eşitliği).

equalKendi işlevi olarak da tanımladığımıza dikkat edin . Bu arrayCompare, birinci dereceden karşılaştırıcımızı başka bir veri türü (Array) bağlamında kullanmak için daha üst düzey bir işlev olarak rolünü vurgular .


Gevşek karşılaştırma

Biz aynı kolaylıkla tanımlanabilir olabilir arrayLooseEqualbir kullanarak ==yerine. Şimdi 1(Number) ile '1'(String) karşılaştırılırken, sonuç true

// looseEqual :: a -> a -> Bool
const looseEqual = x => y =>
  x == y // notice: double equal

// arrayLooseEqual :: [a] -> [a] -> Bool
const arrayLooseEqual =
  arrayCompare (looseEqual)

const xs = [1,2,3]
const ys = ['1','2','3']
console.log (arrayLooseEqual (xs) (ys))    //=> true
// (1 == '1') && (2 == '2') && (3 == '3')  //=> true

Derin karşılaştırma (özyinelemeli)

Muhtemelen bunun sadece sığ bir karşılaştırma olduğunu fark etmişsinizdir. Muhtemelen Tomáš'un çözümü "Doğru Yol ™" dur çünkü derin bir karşılaştırma yapıyor, değil mi?

Eh bizim arrayCompareprosedür derin eşitlik testi bir esinti kılan bir şekilde kullanmak için yeterli çok yönlü ...

// isArray :: a -> Bool
const isArray =
  Array.isArray

// arrayDeepCompare :: (a -> a -> Bool) -> [a] -> [a] -> Bool
const arrayDeepCompare = f =>
  arrayCompare (a => b =>
    isArray (a) && isArray (b)
      ? arrayDeepCompare (f) (a) (b)
      : f (a) (b))

const xs = [1,[2,[3]]]
const ys = [1,[2,['3']]]
console.log (arrayDeepCompare (equal) (xs) (ys)) //=> false
// (1 === 1) && (2 === 2) && (3 === '3')         //=> false

console.log (arrayDeepCompare (looseEqual) (xs) (ys)) //=> true
// (1 == 1) && (2 == 2) && (3 == '3')                 //=> true

Bu kadar basit. Başka bir üst düzey işlev kullanarak derin bir karşılaştırıcı oluşturuyoruz . Bu sefer tamamlamak üzereyiz arrayCompareeğer kontrol eden özel bir karşılaştırıcı kullanılarak ave bdizilerdir. Öyleyse, arrayDeepComparebaşka şekilde yeniden karşılaştırın ave bkullanıcı tarafından belirtilen karşılaştırıcıya ( f) bakın. Bu, derin karşılaştırma davranışını, tek tek öğeleri gerçekte nasıl karşılaştırdığımızdan ayrı tutmamızı sağlar. Yani, gösteriler yukarıdaki örnekte olduğu gibi, derin kullanarak karşılaştırabilirsiniz equal, looseEqualya da başka herhangi karşılaştırıcı yaptığımız.

Çünkü arrayDeepComparecurried edilir yaptığımız gibi, biz kısmen de önceki örneklerde uygulayabilirsiniz

// arrayDeepEqual :: [a] -> [a] -> Bool
const arrayDeepEqual =
  arrayDeepCompare (equal)

// arrayDeepLooseEqual :: [a] -> [a] -> Bool
const arrayDeepLooseEqual =
  arrayDeepCompare (looseEqual)

Bana göre Tomas'ın çözümü içinde bu zaten açık bir iyileşme ben çünkü açıkça gerektiği gibi, benim diziler için sığ veya derin karşılaştırmayı seçin.


Nesne karşılaştırması (örnek)

Şimdi bir dizi nesneniz veya başka bir şey varsa? Belki her nesne aynı iddeğere sahipse bu dizileri "eşit" olarak değerlendirmek istersiniz ...

// idEqual :: {id: Number} -> {id: Number} -> Bool
const idEqual = x => y =>
  x.id !== undefined && x.id === y.id

// arrayIdEqual :: [a] -> [a] -> Bool
const arrayIdEqual =
  arrayCompare (idEqual)

const xs = [{id:1}, {id:2}]
const ys = [{id:1}, {id:2}]
console.log (arrayIdEqual (xs) (ys)) //=> true
// (1 === 1) && (2 === 2)            //=> true

const zs = [{id:1}, {id:6}]
console.log (arrayIdEqual (xs) (zs)) //=> false
// (1 === 1) && (2 === 6)            //=> false

Bu kadar basit. Burada vanilya JS nesneleri kullandım, ancak bu tür karşılaştırıcı herhangi bir nesne türü için işe yarayabilir ; özel nesneleriniz bile. Bu tür bir eşitlik testini desteklemek için Tomáš çözümünün tamamen elden geçirilmesi gerekecektir.

Nesnelerle derin dizi? Problem değil. Çok yönlü, genel işlevler geliştirdik, böylece çok çeşitli kullanım durumlarında çalışacaklar.

const xs = [{id:1}, [{id:2}]]
const ys = [{id:1}, [{id:2}]]
console.log (arrayCompare (idEqual) (xs) (ys))     //=> false
console.log (arrayDeepCompare (idEqual) (xs) (ys)) //=> true

Keyfi karşılaştırma (örnek)

Ya da başka türlü tamamen keyfi bir karşılaştırma yapmak isterseniz? Belki her xbirinin daha büyük olup olmadığını bilmek istiyorum y...

// gt :: Number -> Number -> Bool
const gt = x => y =>
  x > y

// arrayGt :: [a] -> [a] -> Bool
const arrayGt = arrayCompare (gt)

const xs = [5,10,20]
const ys = [2,4,8]
console.log (arrayGt (xs) (ys))     //=> true
// (5 > 2) && (10 > 4) && (20 > 8)  //=> true

const zs = [6,12,24]
console.log (arrayGt (xs) (zs))     //=> false
// (5 > 6)                          //=> false

Az ama öz

Aslında daha az kodla daha fazlasını yaptığımızı görebilirsiniz. arrayCompareKendisi hakkında karmaşık bir şey yok ve yaptığımız özel karşılaştırıcıların her birinin çok basit bir uygulaması var.

Kolaylığı ile, iki diziler karşılaştırılabilir dileyebilir tam olarak nasıl tanımlayabilirsiniz - Sığ, derin, sıkı, gevşek, bazı nesne mülkü veya bazı keyfi hesaplama veya bunların herhangi bir kombinasyonu - hepsi tek bir prosedürü kullanarak , arrayCompare. Belki de bir RegExpkarşılaştırıcı hayal edin ! Çocukların bu normal ifadeleri nasıl sevdiğini biliyorum…

En hızlı mı? Hayır! Ama muhtemelen ikisinin de olması gerekmez. Hız, kodumuzun kalitesini ölçmek için kullanılan tek metrikse, gerçekten harika bir kod çok atılır - Bu yüzden bu yaklaşımı Pratik Yol olarak adlandırıyorum . Ya da belki daha adil olmak, Pratik Bir Yol. Bu açıklama bu cevap için uygundur, çünkü bu cevabın sadece diğer bazı cevaplara kıyasla pratik olduğunu söylemiyorum; nesnel olarak doğrudur. Akıl yürütmesi çok kolay olan çok az kodla yüksek derecede pratiklik elde ettik. Başka hiçbir kod bu açıklamayı kazanamadığımızı söyleyemez.

Bu sizin için "doğru" çözüm mü yapıyor? Karar vermek sizin elinizde . Ve bunu sizin için başka hiç kimse yapamaz; İhtiyaçlarınızın ne olduğunu sadece siz bilirsiniz. Hemen hemen her durumda, akıllı ve hızlı bir şekilde açık, pratik ve çok yönlü bir kod değeri veriyorum. Değer verdiğiniz şey farklı olabilir, bu nedenle sizin için neyin işe yaradığını seçin.


Düzenle

Eski cevabım daha arrayEqualküçük prosedürlere ayrışmaya odaklanmıştı . Bu ilginç bir alıştırma, ama bu soruna yaklaşmanın en iyi (en pratik) yolu değil. İlgileniyorsanız, bu düzeltme geçmişini görebilirsiniz.


8
“en iyi kod türünün yorumlara bile ihtiyacı yoktur” ... söylemekten nefret eder, ancak bu kod daha fazla yorum kullanabilir ve / veya farklı bir ad olabilir - “karşılaştır” oldukça belirsizdir. Eğer doğru okuyorsam, "karşılaştırmak" esasen bir curried özyinelemeli "every" dir. Bence. Yoksa kıvrımlı bir özyinelemeli "bazı" mı? Hmm. Bu, gereğinden fazla düşünmeyi gerektiriyor. Belki de daha iyi bir isim, "eşdeğerlik ilişkisi" nin standart terminolojisinden yararlanarak "diziler Eşdeğer" olacaktır. Ya da, daha net (bana yine de), "özyineli olarak Eşdeğer".
Don Hatch

1
@DonHatch yanıtlama fırsatı için teşekkürler. "Karşılaştır" ile mi demek istediniz arrayCompare? Evet fonksiyonu curried, ama farklıdır someve every.arrayComparekarşılaştırıcı ve karşılaştırılacak iki dizi alır . Herhangi bir rastgele işlev kullanarak dizileri karşılaştırabileceğimiz için özel bir ad seçtim. İşlev, yeni dizi karşılaştırma işlevleri (ör arrayEqual.) Oluşturmak için özelleştirilebilir . Daha iyi bir isim önerebilir misin? Hangi alanların ek yorum veya açıklamaya ihtiyacı olduğunu düşünüyorsunuz? Tartıştığım için mutluyum ^ _ ^
Teşekkürler

1
Benim açımdan henüz net olup olmadığından emin değilim - ama benim açımdan, fonksiyonunuz gerçekten keyfi bir fonksiyon almayı amaçlamıyor , sanmıyorum ... denklik ilişkisi denklik ilişkisi döndürüyor. Bu önemli - bahsettiğim gibi bir çeşit keyfi ikili işlev verilirse, insanların sık sık “karşılaştır” dediği bile mantıklı bir şey yapmaz (sanmıyorum). Bu yüzden "karşılaştırma" yerine "eşdeğer" koymak yararlı olacağını düşünüyorum.
Don Hatch

1
@ftor, yazar: süper yararlı cevap, iyi iş, +1. Geribildirim: Basitliği savunuyorsunuz, ancak pek çok geliştirici için basit veya anlaşılması kolay bir satırda üç ok bulunan bir ifade yoktur. Örn: f => ([x, ... xs]) => ([y, ... ys]) =>. Bunu sürekli kullanıyorum ve “sadece bakmak” yerine zihinsel olarak ayrıştırmak zorunda kaldım. İkinci nokta ftor doğru, her birini kullanın. Sebeplerinizi tartmak bile, dengede sadece benim için değil, aynı zamanda tasarım felsefenizi çıkarmaya çalışırken bakış açınızdan daha iyi görünüyor.
whitneyland

1
Bunun bir öğrenim yeri olduğunu anlıyorum, ancak burada işlevsel stili inceleyen ortalama bir programcının herhangi bir körili işlevi kıvrılmamış bir işleve dönüştürebileceğini varsayıyorum. Cevabım, bu stilin kendi programınızda kullanılması gerektiği fikrini vermez - kıvrılmamış yazın, kendi girinti kurallarınızı kullanarak yazın, istediğiniz gibi yazın - Cevaplarımı ifade ettiğine inandığım bir tarzda yazıyorum program iyi. Ayrıca başkalarını programlarımızı sözdizimsel olarak ifade etme şeklimize meydan okumaya davet etmek istiyorum
Teşekkürler

54

Orijinal sorunun ruhuna göre:

İki diziyi karşılaştırmak istiyorum ... ideal, verimli . Hiçbir şey fantezi , aynı ise doğru ve değilse yanlış.

Aşağıdaki sonuçlarla (hızlı ila yavaş) burada önerilen daha basit önerilerden bazılarında performans testleri yürütüyorum :

süre (% 67) Tim Down tarafından

var i = a1.length;
while (i--) {
    if (a1[i] !== a2[i]) return false;
}
return true

her (% 69) user2782196 tarafından

a1.every((v,i)=> v === a2[i]);

DEI'lerle azaltma (% 74)

a1.reduce((a, b) => a && a2.includes(b), true);

katılması ve toString (% 78) Gaizka Allende ve Vivek tarafından

a1.join('') === a2.join('');

a1.toString() === a2.toString();

Victor Palomo tarafından yarım (% 90)

a1 == a2.toString();

radtek tarafından stringify (% 100)

JSON.stringify(a1) === JSON.stringify(a2);

Not diziler, tek boyutlu diziler sıralanır varsayar aşağıdaki örnekleri. .lengthkarşılaştırması, ortak bir karşılaştırma ölçütü için kaldırılmıştır ( a1.length === a2.lengthönerilerden herhangi birine ekleyin ve ~% 10'luk bir performans artışı elde edersiniz). Her birinin hızını ve sınırını bilerek sizin için en uygun olan çözümleri seçin.

İlgisiz not: İnsanların tüm tetikleyici-mutlu John Waynes'i bu soruya mükemmel meşru cevaplarda aşağı oy düğmesinde aldıklarını görmek ilginç.


Bağlantı boş bir test açar.
Alexander Abakumov

Dizi boyutunu vurursanız, bu sayılar geçerli olmaz (özellikle yaklaşma azaltma). Array.from({length: 1000}).map((a,v)=> $ {V} ile deneyin.padStart(10,2));
Narayon

sadece sığ dizi için çalışıyor
Ramesh Rajendran

28

Tomáš Zato'nun cevabını temel alarak, sadece dizileri yinelemenin en hızlı olduğunu kabul ediyorum. Ek olarak (diğerlerinin belirttiği gibi), işlev karşılaştırmak yerine eşit / eşit olarak adlandırılmalıdır. Bunun ışığında, benzerlik için dizileri karşılaştırma işlevini değiştirdim - yani aynı öğelere, ancak sıra dışı - kişisel kullanım için ve herkesin görmesi için buraya atacağımı düşündüm.

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

Bu işlev varsayılanı true olan ek bir katı parametresi alır. Bu katı parametre, dizilerin hem içeriklerde hem de bu içeriklerin sıralamasında tamamen eşit olması veya sadece aynı içerikleri içermesi gerektiğini tanımlar.

Misal:

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

Ben de fonksiyonu ve bu örnek ile hızlı bir jsfiddle yazdım:
http://jsfiddle.net/Roundaround/DLkxX/


12

Bunun birçok yanıtı olmasına rağmen, yardımcı olduğuna inandığım bir cevap:

const newArray = [ ...new Set( [...arr1, ...arr2] ) ]

Dizinin yapısının nasıl görüneceği sorusunda belirtilmedi, bu yüzden dizileri veya dizinizdeki nesneleri iç içe geçirmeyeceğinizden eminseniz (bu bana geldi, bu yüzden buna geldim cevap) yukarıdaki kod çalışacaktır.

Olan şey şu ki, her iki diziyi birleştirmek için yayılma operatörü (...) kullanıyoruz, sonra yinelenenleri ortadan kaldırmak için Set kullanıyoruz. Bir kez sahip olduklarında, boyutlarını karşılaştırabilirsiniz, eğer üç dizinin hepsi aynı boyuta sahipse, gitmek için iyidir.

Bu cevap aynı zamanda , öğelerin sırasını da göz ardı ediyor , dediğim gibi, kesin durum bana oldu, bu yüzden belki de aynı durumda olan biri buraya gelebilir (yaptığım gibi).


Edit1.

Dmitry Grinko'nun sorusunu cevaplarken: "Neden burada forma operatörü (...) kullandınız - ... yeni Set? Çalışmıyor"

Bu kodu düşünün:

const arr1 = [ 'a', 'b' ]
const arr2 = [ 'a', 'b', 'c' ]
const newArray = [ new Set( [...arr1, ...arr2] ) ]
console.log(newArray)

Alacaksınız

[ Set { 'a', 'b', 'c' } ]

Bu değerle çalışmak için bazı Set özelliklerini kullanmanız gerekir (bkz. Https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set ). Öte yandan, bu kodu kullandığınızda:

const arr1 = [ 'a', 'b' ]
const arr2 = [ 'a', 'b', 'c' ]
const newArray = [ ...new Set( [...arr1, ...arr2] ) ]
console.log(newArray)

Alacaksınız

[ 'a', 'b', 'c' ]

Bu fark, birincisi bana bir Set verecekti, o Setin boyutunu alabileceğim için de işe yarayacaktı, ancak ikincisi bana ihtiyacım olan diziyi, çözünürlüğe daha doğrudan olanı veriyor.


Neden burada forma operatörü (...) kullandınız - ... yeni Set? Çalışmıyor.
Dmitry Grinko

Dmitry Grinko Sanırım Edit1'deki sorunuzu cevapladım. Ama her iki cevap da size yol gösterebileceğinden, 'işe yaramaz' diyerek ne demek istediğinizden emin değilim
Jeferson Euclides

10

JSON.encode ile aynı satırlarda join () kullanılır.

function checkArrays( arrA, arrB ){

    //check if lengths are different
    if(arrA.length !== arrB.length) return false;


    //slice so we do not effect the original
    //sort makes sure they are in order
    //join makes it a string so we can do a string compare
    var cA = arrA.slice().sort().join(","); 
    var cB = arrB.slice().sort().join(",");

    return cA===cB;

}

var a = [1,2,3,4,5];
var b = [5,4,3,2,1];
var c = [1,2,3,4];
var d = [1,2,3,4,6];
var e = ["1","2","3","4","5"];  //will return true

console.log( checkArrays(a,b) );  //true
console.log( checkArrays(a,c) );  //false
console.log( checkArrays(a,d) );  //false
console.log( checkArrays(a,e) );  //true

Tek sorun, son karşılaştırma testlerini yapan türleri önemsiyorsanız. Türleri önemsiyorsanız, döngü yapmanız gerekecektir.

function checkArrays( arrA, arrB ){

    //check if lengths are different
    if(arrA.length !== arrB.length) return false;

    //slice so we do not effect the orginal
    //sort makes sure they are in order
    var cA = arrA.slice().sort(); 
    var cB = arrB.slice().sort();

    for(var i=0;i<cA.length;i++){
         if(cA[i]!==cB[i]) return false;
    }

    return true;

}

var a = [1,2,3,4,5];
var b = [5,4,3,2,1];
var c = [1,2,3,4];
var d = [1,2,3,4,6];
var e = ["1","2","3","4","5"];

console.log( checkArrays(a,b) );  //true
console.log( checkArrays(a,c) );  //false
console.log( checkArrays(a,d) );  //false
console.log( checkArrays(a,e) );  //false

Sipariş aynı kalıyorsa, sadece bir döngüden daha fazla, sıralama gerekmez.

function checkArrays( arrA, arrB ){

    //check if lengths are different
    if(arrA.length !== arrB.length) return false;


    for(var i=0;i<arrA.length;i++){
         if(arrA[i]!==arrB[i]) return false;
    }

    return true;

}

var a = [1,2,3,4,5];
var b = [5,4,3,2,1];
var c = [1,2,3,4];
var d = [1,2,3,4,6];
var e = ["1","2","3","4","5"];

console.log( checkArrays(a,a) );  //true
console.log( checkArrays(a,b) );  //false
console.log( checkArrays(a,c) );  //false
console.log( checkArrays(a,d) );  //false
console.log( checkArrays(a,e) );  //false

3
Bu sadece belirli dizilerde işe yarar ve büyük dizilerde çok yavaş olacaktır.
Tomáš Zato - Monica

2
JSON oluşturmak da döngü yapıyor, sadece (ya da öyle görünüyor) bunu bilmiyorsunuz. Döngünün yanı sıra, JSON oluşturmak da daha fazla bellek gerektirir - karşılaştırmadan önce söz konusu dizilerin 2 dize temsilini oluşturur. Downwote işlevi, en iyiden en kötüye cevapları sıralamak için uygulanır. Bence cevabınız iyi bir cevap değil, bu yüzden cevap vermedim.
Tomáš Zato - Monica

2
Üzgünüm, sadece JSON yerine dedim .join(). Belki ikinci çözümünüzü birincil olarak (daha iyi olduğu için, çok boyutlu dizilere karşı dişsiz olsa da) ifade ettiyseniz, sizi bu şekilde yargılamam. Şimdiye kadar, dizeleri dizelere dönüştüren tüm yanıtları indirdim. Ayrıca, bilmeniz gerekmesi durumunda, doğru olanı kullanan her şeyi iptal ettim. Bu @Tim Down'un yanıtı ve Bireys'in yanıtı demektir.
Tomáš Zato - Monica

6
İlk sürüm FAILS:, checkArrays([1,2,3] , ["1,2",3]) == trueve olmasını istediğiniz şey çok düşüktür!
Doin

2
@epascarello: Evet, ancak (önerdiğiniz çok uzun ayırıcının verimsizliğinin yanı sıra) checkArrays () işlevinin hatalı çalıştığı kenar durumları (dizinin ayırıcıda bir dize içerdiği yerlerde) olacağı anlamına gelir . Dizilerin içeriği hakkında bir şeyler biliyorsanız bu sorun olmayabilir (böylece dizi öğelerinde olmayacağından emin olduğunuz bir ayırıcı seçebilirsiniz), ancak genel bir dizi karşılaştırması yazmaya çalışıyorsanız fonksiyonu, daha sonra join()bu gibi kullanarak ustaca buggy yapar!
Doin

7

İşte bir Typcript sürümü:

//https://stackoverflow.com/a/16436975/2589276
export function arraysEqual<T>(a: Array<T>, b: Array<T>): boolean {
    if (a === b) return true
    if (a == null || b == null) return false
    if (a.length != b.length) return false

    for (var i = 0; i < a.length; ++i) {
        if (a[i] !== b[i]) return false
    }
    return true
}

//https://stackoverflow.com/a/16436975/2589276
export function arraysDeepEqual<T>(a: Array<T>, b: Array<T>): boolean {
    return JSON.stringify(a) === JSON.stringify(b)
}

Mocha için bazı test vakaları:

it('arraysEqual', function () {
    let a = [1,2]
    let b = [1,2]
    let c = [2,3]
    let d = [2, 3]
    let e = ['car','apple','banana']
    let f = ['car','apple','banana']
    let g = ['car','apple','banan8']

    expect(arraysEqual(a, b)).to.equal(true)
    expect(arraysEqual(c, d)).to.equal(true)
    expect(arraysEqual(a, d)).to.equal(false)
    expect(arraysEqual(e, f)).to.equal(true)
    expect(arraysEqual(f, g)).to.equal(false)
})

it('arraysDeepEqual', function () {
    let a = [1,2]
    let b = [1,2]
    let c = [2,3]
    let d = [2, 3]
    let e = ['car','apple','banana']
    let f = ['car','apple','banana']
    let g = ['car','apple','banan8']
    let h = [[1,2],'apple','banan8']
    let i = [[1,2],'apple','banan8']
    let j = [[1,3],'apple','banan8']

    expect(arraysDeepEqual(a, b)).to.equal(true)
    expect(arraysDeepEqual(c, d)).to.equal(true)
    expect(arraysDeepEqual(a, d)).to.equal(false)
    expect(arraysDeepEqual(e, f)).to.equal(true)
    expect(arraysDeepEqual(f, g)).to.equal(false)
    expect(arraysDeepEqual(h, i)).to.equal(true)
    expect(arraysDeepEqual(h, j)).to.equal(false)
})

6

Chai onay kütüphanesi ile Mocha gibi bir test çerçevesi kullanıyorsanız , dizileri karşılaştırmak için derin eşitlik kullanabilirsiniz .

expect(a1).to.deep.equal(a2)

Bu, ancak dizilerin karşılık gelen dizinlerde eşit öğelere sahip olması durumunda doğru olmalıdır.


6

Yalnızca iki sayı veya dizgi dizisi ise, bu hızlı tek satırlık bir dizidir

const array1 = [1, 2, 3];
const array2 = [1, 3, 4];
console.log(array1.join(',') === array2.join(',')) //false

const array3 = [1, 2, 3];
const array4 = [1, 2, 3];
console.log(array3.join(',') === array4.join(',')) //true

const dizi1 = [1]; const dizi2 = [1, 1]; console.log (array1.join ('') === array2.join ('')) // true değerini döndürür
Dan M.

olmamalıdır: array1.join ('') '1' ve array2.join ('') '11'
Gaizka Allende

Pardon yazım yanlışı. İlk dizi olmalıdır [11]. Bunun neden olduğu ve nasıl düzeltileceği konusunda oldukça açık.
Dan M.

Ne hakkında olduğundan emin değilim, oldukça basit: [1] .join () "1" ve [1,1] .join () "1,1", bu yüzden asla eşit olmayacaklar
Gaizka Allende

lütfen yorumumu daha dikkatli okuyun. Hâlâ görmüyorsanız, bir yağma atın ideone.com/KFu427
Dan M.

5

Benim durumumda, karşılaştırılan diziler yalnızca sayı ve dizeler içeriyor. Bu işlev, dizilerin aynı öğeleri içerip içermediğini gösterir.

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

Test edelim!

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

Soru sizden sıralamanızı istemediğinden, çözümünüz gibi örnekler için yanlıştır are_arrs_equal([1,2], [2,1]). Ayrıca, dizgi oluşturmanın neden gereksiz, kırılgan ve yanlış olduğuna ilişkin diğer tartışmalara da bakın.
Modlarına iyi

are_arrs_equal([1,2], [2,1])truebeklendiği gibi döner . Belki de bu çözüm ideal değil, ama benim için çalıştı.
yesnik

Sorun tam olarak budur, bu ikisi sıralı bir veri yapısı için "eşit" kelimesinin aklı başında değildir . Bunlar dizilerdir, kümeler değildir ve eşitlik ayarlamak istiyorsanız buna böyle demelisiniz - ve farklı bir soruya cevap veriyorsunuz. :-)
Modlarına iyi

1
Yukarıdaki yorumlara katılıyorum, ancak bu çözüm benim için siparişin önemli olmadığı basit tamsayı dizilerimde de işe yarıyor, bu yüzden kullanacağım.
tomazahlin

1
Başarısız are_arrs_match([1,2], ["1,2"])(döndürür true). Ve the sort()aramanın giriş dizilerini değiştireceğini unutmayın - bu istenmeyebilir.
try-catch-nihayet

5

Bu, sıralanmamış 2 diziyi karşılaştırır:

function areEqual(a, b) {
  if ( a.length != b.length) {
    return false;
  }
  return a.filter(function(i) {
    return !b.includes(i);
  }).length === 0;  
}

Pahalı olmasına rağmen (hesaplama kaynakları açısından), bu, çeşitli türler için iyi olması gereken ve sıralamaya dayanmayan sağlam bir çözümdür!
user3.1415927


4

Bunu every( https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/every ) kullanarak işlevsel bir şekilde yapabiliriz

function compareArrays(array1, array2) {
    if (array1.length === array2.length)
        return array1.every((a, index) => a === array2[index])
    else
        return false
}

// test
var a1 = [1,2,3];
var a2 = [1,2,3];

var a3 = ['a', 'r', 'r', 'a', 'y', '1']
var a4 = ['a', 'r', 'r', 'a', 'y', '2']

console.log(compareArrays(a1,a2)) // true
console.log(compareArrays(a1,a3)) // false
console.log(compareArrays(a3,a4)) // false

4

Her iki dizi de aynı öğeye sahip ancak aynı sırada olmadığında, kodunuz durumu uygun şekilde işlemeyecektir.

Koduma, öğeleri sayı olan iki diziyi karşılaştıran örneğinize bir göz atın, diğer öğe türleri için (.toString () yerine .join () kullanarak) değiştirebilir veya genişletebilirsiniz.

var a1 = [1,2,3];
var a2 = [1,2,3];
const arraysAreEqual = a1.sort().toString()==a2.sort().toString();
// true if both arrays have same elements else false
console.log(arraysAreEqual);


3

Herer'in çözümü:

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

Herhangi bir iç içe veri yapısıyla çalışır ve nesnelerin yöntemlerini açıkça yok sayar. Object.prototype'i bu yöntemle genişletmeyi bile düşünmeyin, bunu bir kez denediğimde jQuery kırdı;)

Çoğu dizide hala serileştirme çözümlerinin çoğundan daha hızlıdır. Muhtemelen nesne kayıtları dizileri için en hızlı karşılaştırma yöntemidir.


iyi değil! bunlar doğru: equal({}, {a:1})ve equal({}, null)ve bu hatalar dışarı:equal({a:2}, null)
kristianlm

3
JSON.stringify(collectionNames).includes(JSON.stringify(sourceNames)) ?  array.push(collection[i]) : null

Ben böyle yaptım.


İyi bir çözüm - ama bazı durumlarda, ilkel veya derin iç içe diziler gibi her zaman amaçlandığı gibi çalışmayacak mı acaba? Umarım her koşulda çalışır
Ben Rondeau

3

2 dizinin karşılaştırılması:

var arr1 = [1,2,3];
var arr2 = [1,2,3];

function compare(arr1,arr2)
{
  if((arr1 == arr2) && (arr1.length == arr2.length))
    return true;
  else
    return false;
}

çağrı fonksiyonu

var isBool = compare(arr1.sort().join(),arr2.sort().join());

=== diziler için beklendiği gibi davranmadığından bu yanıt işe yaramaz.
Michael Yang

Her ne kadar === burada bir önemi olmasa da cevap işe yarıyor (sort () sadece dizide çalıştığından). == bile çalışacaktır.
Amay Kulkarni

Kendiniz deneyin; bu kodu çalıştırırsanız yanlış yazdırır. Bunun nedeni, dizilerin referans değerlerinin gerçek değerleri yerine == ve === ile karşılaştırılmasıdır. == ve === yalnızca ilkel tür karşılaştırması içindir.
Michael Yang

Doğru döner, biz kullandık, ama şimdi '===' necassary olmadığı için kaldırdım
Amay Kulkarni

Ah, bir dizgeye dönüştürdüğünüzü ve sıraladıktan ve katıldıktan sonra işlevi çağırdığınızı fark etmedim; özür dilerim.
Michael Yang

3

Ben sade JSve ile inanıyorum ECMAScript 2015ki bu tatlı ve anlaşılması kolay.

var is_arrays_compare_similar = function (array1, array2) {

    let flag = true;

    if (array1.length == array2.length) {

        // check first array1 object is available in array2 index
        array1.every( array_obj => {
            if (flag) {
                if (!array2.includes(array_obj)) {
                    flag = false;
                }
            }
        });

        // then vice versa check array2 object is available in array1 index
        array2.every( array_obj => {
            if (flag) {
                if (!array1.includes(array_obj)) {
                    flag = false;
                }
            }
        });

        return flag;
    } else {
        return false;
    }

}

umarım birine yardım eder.


1
Tam tersi kontrol neden gereklidir? Dizilerin aynı boyutta olduğunu biliyoruz, bu nedenle dizi1'deki her öğe dizi2'de de bulunursa; neden dizi2'deki her öğenin de dizi1'de olduğunu kontrol etmeliyiz?
JeffryHouser

2

Tomáš Zato fikrini genişletiyor. Tomas Array.prototype.compare, Array.prototype.compareIdentical adı verilen bir bulaşıcı olmalıdır.

Geçer:

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

Ancak başarısız olur:

[[1, 2, [3, 2]],1, 2, [3, 2]].compareIdentical([1, 2, [3, 2],[1, 2, [3, 2]]])

İşte daha iyi (bence) sürüm:

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/


2
-1. Verdiğiniz örnek üzerinde 'başarısız' olursa, o zaman sadece keyfi olarak 'başarısız' tanımı için durum böyledir. Neden bu iki farklı dizinin eşit kabul edilmesini beklersiniz? Burada hangi 'eşitlik' kavramını uygulamaya çalıştığınızı veya bunun neden mantıklı veya yararlı olduğunu açıklamamışsınız, ancak çok boyutlu dizilerin tek boyutlu olarak çökmüş gibi karşılaştırılmasını istiyorsunuz gibi görünüyor olanlar. Eğer öyleyse, bunu başaramadınız bile: [1,2] .compare ([[1,2]]), Tomáš'da olduğu gibi versiyonunuzda yanlışlık veriyor.
Mark Amery

Çıkarım yapabileceğimden yola çıkarak [1, 2, 3, 4] ve [1, 3, 2, 4] 'ün eşit olarak karşılaştırılması gerektiğini söylüyor (Düzen önemli değil).
Gautham Badhrinathan

2
var a1 = [1,2,3,6];
var a2 = [1,2,3,5];

function check(a, b) {
  return (a.length != b.length) ? false : 
  a.every(function(row, index) {
    return a[index] == b[index];
  });
}  

check(a1, a2);

////// VEYA ///////

var a1 = [1,2,3,6];
var a2 = [1,2,3,6];

function check(a, b) {
  return (a.length != b.length) ? false : 
  !(a.some(function(row, index) {
    return a[index] != b[index];
  }));
}  

check(a1, a2)

Yukarıdaki gibi gerekli koşulu tatmin edersek tamamen tekrarlamayacak bazı işlevleri de yapabilirsiniz
Vasanth

2

Çok az kod içeren başka bir yaklaşım ( Array reduce ve Array kullanarak şunları içerir ):

arr1.length == arr2.length && arr1.reduce((a, b) => a && arr2.includes(b), true)

Sipariş eşitliğini de karşılaştırmak isterseniz:

arr1.length == arr2.length && arr1.reduce((a, b, i) => a && arr2[i], true)
  • lengthBir dizideki elemanların kümesi diğeri yalnızca bir alt kümesine olmadığını kontrol olmasını sağlar.

  • İndirgeyici bir dizi boyunca yürümek ve diğer dizideki her öğeyi aramak için kullanılır. Bir öğe bulunmazsa, azaltma işlevi geri döner false.

    1. İlk örnekte, bir öğenin dahil edildiği test ediliyor
    2. İkinci örnek de siparişi kontrol eder

1
Bu cevabı daha net hale getirmek için kodunuzu biraz açıklayabilir misiniz?
ted

1. bir dizinin diğerinin bir alt kümesi olmadığından emin olmak için dizi uzunluklarını karşılaştırın
DEls

2. Bir dizide gezinmek ve diğer dizideki her öğeyi aramak için redüktör kullanın. Bir öğe bulunmazsa, azaltma işlevi 'false'
değerini

@DEls: açıklamanızı cevaba düzenledi (hafifçe değiştirildi ve uzatıldı). Artık yorumlarınızı kaldırabilir ve ilk yorumu ve bunu eski olarak işaretleyebilirsiniz.
try-catch-nihayet

2

Basit bir yaklaşım:

function equals(a, b) {
    if ((a && !b) || (!a && b) || (!a && !b) || (a.length !== b.length)) {
        return false;
    }

    var isDifferent = a.some(function (element, index) { 
        return element !== b[index];
    });

    return !isDifferent;
}

2

Zaten bazı harika cevaplar.Ancak dizileri karşılaştırmada güvenilir olduğu kanıtlanan başka bir fikri paylaşmak istiyorum. JSON.stringify () öğesini kullanarak iki diziyi karşılaştırabiliriz . Diziyi bir dize oluşturur ve böylece iki diziden iki dizeyi eşitlik için karşılaştırır.

JSON.stringify([1,{a:1},2]) == JSON.stringify([1,{a:1},2]) //true

JSON.stringify([1,{a:1},2]) == JSON.stringify([1,{a:2},2]) //false

JSON.stringify([1,{a:1},2]) == JSON.stringify([1,{a:2},[3,4],2]) //false

JSON.stringify([1,{a:1},[3,4],2]) == JSON.stringify([1,{a:2},[3,4],2]) //false

JSON.stringify([1,{a:2},[3,4],2]) == JSON.stringify([1,{a:2},[3,4],2]) //true

JSON.stringify([1,{a:2},[3,4],2]) == JSON.stringify([1,{a:2},[3,4,[5]],2]) //false

JSON.stringify([1,{a:2},[3,4,[4]],2]) == JSON.stringify([1,{a:2},[3,4,[5]],2]) //false

JSON.stringify([1,{a:2},[3,4,[5]],2]) == JSON.stringify([1,{a:2},[3,4,[5]],2]) //true

2

Özyinelemeli ve NESTED dizileri üzerinde çalışır :

function ArrEQ(a1,a2){
   return( 
        //:Are both elements arrays?
        Array.isArray(a1)&&Array.isArray(a2) 
        ?
        //:Yes: Test each entry for equality:
        a1.every((v,i)=>(ArrEQ(v,a2[i])))
        :
        //:No: Simple Comparison:
        (a1===a2)
   );;
};;

console.log( "Works With Nested Arrays:" );
console.log( ArrEQ( 
    [1,2,3,[4,5,[6,"SAME/IDENTICAL"]]],
    [1,2,3,[4,5,[6,"SAME/IDENTICAL"]]]
));;     
console.log( ArrEQ( 
    [1,2,3,[4,5,[6,"DIFFERENT:APPLES" ]]],
    [1,2,3,[4,5,[6,"DIFFERENT:ORANGES"]]]
));;  

2

NESTED dizileri olan MULTIPLE argümanlarıyla çalışır :

//:Return true if all of the arrays equal.
//:Works with nested arrays.
function AllArrEQ(...arrays){
    for(var i = 0; i < (arrays.length-1); i++ ){
        var a1 = arrays[i+0];
        var a2 = arrays[i+1];
        var res =( 
            //:Are both elements arrays?
            Array.isArray(a1)&&Array.isArray(a2) 
            ?
            //:Yes: Compare Each Sub-Array:
            //:v==a1[i]
            a1.every((v,i)=>(AllArrEQ(v,a2[i])))
            :
            //:No: Simple Comparison:
            (a1===a2)
        );;
        if(!res){return false;}
    };;
    return( true );
};;

console.log( AllArrEQ( 
        [1,2,3,[4,5,[6,"ALL_EQUAL"   ]]],
        [1,2,3,[4,5,[6,"ALL_EQUAL"   ]]],
        [1,2,3,[4,5,[6,"ALL_EQUAL"   ]]],
        [1,2,3,[4,5,[6,"ALL_EQUAL"   ]]],
));; 

2
In a simple way uning stringify but at same time thinking in complex arrays:

**Simple arrays**:  
var a = [1,2,3,4];  
var b = [4,2,1,4];  
JSON.stringify(a.sort()) === JSON.stringify(b.sort()) // true  

**Complex arrays**:  
var a = [{id:5,name:'as'},{id:2,name:'bes'}];  
var b = [{id:2,name:'bes'},{id:5,name:'as'}];  
JSON.stringify(a.sort(function(a,b) {return a.id - b.id})) === JSON.stringify(b.sort(function(a,b) {return a.id - b.id})) // true  

**Or we can create a sort function**  

function sortX(a,b) {  
return a.id -b.id; //change for the necessary rules  
}  
JSON.stringify(a.sort(sortX)) === JSON.stringify(b.sort(sortX)) // true  
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.