Bagaimana cara membandingkan array dalam JavaScript?

989

Saya ingin membandingkan dua array ... idealnya, efisien. Tidak ada yang mewah, hanya truejika mereka identik, dan falsejika tidak. Tidak mengherankan, operator perbandingan sepertinya tidak berfungsi.

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

JSON menyandikan setiap array, tetapi apakah ada cara yang lebih cepat atau "lebih baik" untuk hanya membandingkan array tanpa harus beralih melalui setiap nilai?

Julian H. Lam
sumber
5
Anda bisa membandingkan panjangnya terlebih dahulu, dan jika mereka sama nilainya masing-masing.
TJHeuvel
55
Apa yang membuat dua array sama untuk Anda? Elemen yang sama? Urutan elemen yang sama? Pengkodean sebagai JSON hanya berfungsi selama elemen array dapat diserialisasi ke JSON. Jika array bisa berisi objek, seberapa dalam Anda akan pergi? Kapan dua benda "sama"?
Felix Kling
48
@FelixKling, mendefinisikan "kesetaraan" jelas merupakan topik yang halus, tetapi bagi orang yang datang ke JavaScript dari bahasa tingkat tinggi, tidak ada alasan untuk kekonyolan ([] == []) == false.
Alex D
4
@AlexD sepertinya array menggunakan persamaan referensi yang adalah apa yang Anda harapkan. Akan sangat mengerikan jika Anda tidak bisa melakukan itu
JonnyRaa
3
@AlexD Saya agak tidak bisa memikirkan bahasa di mana ini tidak terjadi. Dalam C ++, Anda akan membandingkan dua petunjuk - salah. Di Jawa, Anda melakukan hal yang sama seperti di javascript. Dalam PHP, sesuatu di belakang layar akan berputar melalui array - apakah Anda menyebut PHP bahasa tingkat yang lebih tinggi?
Tomáš Zato - Reinstate Monica

Jawaban:

877

Untuk membandingkan array, mengulanginya dan membandingkan setiap nilai:

Membandingkan array:

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

Pemakaian:

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

Anda mungkin berkata " Tetapi jauh lebih cepat untuk membandingkan string - tidak ada loop ... " baik, maka Anda harus mencatat ada loop. Loop rekursif pertama yang mengubah Array menjadi string dan kedua, yang membandingkan dua string. Jadi metode ini lebih cepat dari penggunaan string .

Saya percaya bahwa jumlah data yang lebih besar harus selalu disimpan dalam array, bukan pada objek. Namun jika Anda menggunakan objek, mereka dapat sebagian juga dibandingkan.
Begini caranya:

Membandingkan objek:

Saya telah menyatakan di atas, bahwa dua instance objek tidak akan pernah sama, bahkan jika mereka berisi data yang sama saat ini:

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

Ini memiliki alasan, karena mungkin ada, misalnya variabel pribadi dalam objek.

Namun, jika Anda hanya menggunakan struktur objek untuk memuat data, perbandingan masih dimungkinkan:

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

Namun, ingat bahwa ini adalah untuk melayani dalam membandingkan JSON seperti data, bukan instance kelas dan hal-hal lainnya. Jika Anda ingin membandingkan objek yang lebih rumit, lihat jawaban ini dan fungsinya sangat panjang .
Untuk membuatnya bekerja, Array.equalsAnda harus sedikit mengedit fungsi aslinya:

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

Saya membuat alat uji kecil untuk kedua fungsi .

Bonus: Arang bersarang dengan indexOfdancontains

Samy Bencherif telah menyiapkan fungsi yang berguna untuk kasus Anda mencari objek tertentu dalam array bersarang, yang tersedia di sini: https://jsfiddle.net/SamyBencherif/8352y6yw/

Tomáš Zato - Pasang kembali Monica
sumber
27
Jika Anda ingin melakukan perbandingan yang ketat menggunakan this[i] !== array[i]bukan !=.
Tim S.
38
Metode Anda harus dipanggil equalsbukan compare. Setidaknya dalam .NET, bandingkan biasanya mengembalikan int yang ditandai yang menunjukkan objek mana yang lebih besar dari yang lain. Lihat: Pembanding . Bandingkan .
Oliver
15
Tidak hanya ini cara yang tepat untuk melakukannya, itu juga jauh lebih efisien. Berikut ini skrip jsperf cepat yang saya siapkan untuk semua metode yang disarankan dalam pertanyaan ini. jsperf.com/comparing-arrays2
Tolga E
96
Mengubah prototipe tipe bawaan bukan cara yang tepat
Jasper
31
Selain itu, ini bukan tentang apakah mudah untuk menulis ulang, ini tentang fakta bahwa jawaban tidak boleh merekomendasikan sesuatu yang dianggap praktik buruk ( developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/… ) dan harusnya pasti tidak melakukan ini di bawah tajuk "Cara yang benar"
Jasper
386

Meskipun ini hanya berfungsi untuk array skalar (lihat catatan di bawah), ini singkat:

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

Rr, dalam ECMAScript 6 / CoffeeScript / TypeScript dengan Fungsi Panah:

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

(Catatan: 'skalar' di sini berarti nilai yang dapat dibandingkan secara langsung menggunakan ===. Jadi: angka, string, objek dengan referensi, fungsi dengan referensi. Lihat referensi MDN untuk info lebih lanjut tentang operator perbandingan).

MEMPERBARUI

Dari apa yang saya baca dari komentar, mengurutkan array dan membandingkan dapat memberikan hasil yang akurat:

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

Misalnya:

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

Maka kode di atas akan memberi true

pengguna2782196
sumber
19
Saya suka ini, meskipun pembaca harus sadar ini hanya berfungsi pada array yang diurutkan.
Ellen Spertus
13
Ia bekerja pada semua jenis array, disortir atau tidak @espertus
Michał Miszczyszyn
36
Ya persis. Fungsi ini seharusnya membandingkan dua array, tidak masalah apakah mereka diurutkan atau tidak, elemen berurutannya harus sama.
Michał Miszczyszyn
22
@ Espertus Memang, itu tidak akan mengembalikan true jika elemen tidak memiliki urutan yang sama persis di kedua array. Namun, tujuan pemeriksaan kesetaraan bukan untuk memeriksa apakah mereka mengandung elemen yang sama tetapi untuk memeriksa apakah mereka memiliki elemen yang sama dalam urutan yang sama.
Quentin Roy
7
Jika Anda ingin memeriksa apakah kedua array sama, berisi item yang tidak disortir yang sama (tetapi tidak digunakan beberapa kali), Anda dapat menggunakan 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];tidak akan berfungsi seperti yang diharapkan)
mems
208

Saya suka menggunakan perpustakaan Underscore untuk proyek pengkodean array / objek berat ... di Underscore dan Lodash apakah Anda membandingkan array atau objek yang hanya terlihat seperti ini:

_.isEqual(array1, array2)   // returns a boolean
_.isEqual(object1, object2) // returns a boolean
Jason Boerner
sumber
22
Perhatikan bahwa pesanan penting _.isEqual([1,2,3], [2,1,3]) => false
Vitaliy Alekask
3
atau jika Anda hanya menginginkan isEqualfungsionalitasnya, Anda selalu dapat menggunakan modul
lodash.isequal
6
Anda mungkin dapat menggunakan _.difference (); jika pesanan tidak masalah bagi Anda
Ronan Quillevere
5
Kita dapat mengurutkan array sebelum pemeriksaan ini jika pesanan tidak masalah_.isEqual([1,2,3].sort(), [2,1,3].sort()) => true
Filype
IMHO jawaban yang paling ringkas dan langsung :-)
Kieran Ryan
121

Ini menurut saya adalah cara paling sederhana untuk melakukannya menggunakan JSON stringify, dan ini mungkin solusi terbaik dalam beberapa situasi:

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

Ini mengubah objek a1dan a2menjadi string sehingga mereka dapat dibandingkan. Urutan penting dalam kebanyakan kasus, untuk itu dapat mengurutkan objek menggunakan algoritma pengurutan yang ditunjukkan pada salah satu jawaban di atas.

Harap dicatat bahwa Anda tidak lagi membandingkan objek tetapi representasi string objek. Mungkin tidak persis seperti yang Anda inginkan.

radtek
sumber
jawaban yang bagus tetapi mengapa [] == [] kembali salah? keduanya adalah objek sederhana lalu mengapa?
Pardeep Jain
4
@ PassardJain, ini karena secara default, operator kesetaraan dalam ECMAScript untuk Objek mengembalikan true ketika mereka merujuk lokasi memori yang sama. Coba var x = y = []; // sekarang kesetaraan kembali benar.
radtek
7
hanya untuk dicatat bahwa fungsi JSON strify tidak cepat. Digunakan dengan array yang lebih besar pasti akan menyebabkan lag.
Lukas Liesis
6
Pertanyaan khusus menanyakan apakah ada cara yang lebih baik / lebih cepat daripada menggunakan JSON.stringify.
Don Hatch
Ini menjadi lebih rinci tentang mengapa ini bisa menjadi solusi yang baik untuk beberapa situasi.
radtek
61

Tidak jelas apa yang Anda maksud dengan "identik". Misalnya, apakah array adan di bbawahnya sama (perhatikan array bersarang)?

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

Berikut adalah fungsi perbandingan array yang dioptimalkan yang membandingkan elemen yang sesuai dari setiap array pada gilirannya menggunakan kesetaraan yang ketat dan tidak melakukan perbandingan berulang elemen array yang merupakan array itu sendiri, yang berarti bahwa untuk contoh di atas, arraysIdentical(a, b)akan kembali false. Ini berfungsi dalam kasus umum, yang join()tidak akan digunakan JSON dan solusi:

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;
};
Tim Down
sumber
@ ASDF: Tidak jelas dari pertanyaan apa artinya "identik". Jelas jawaban ini hanya melakukan pemeriksaan dangkal. Saya akan menambahkan catatan.
Tim Down
ini gagal untuk arraysIdentical ([1, 2, [3, 2]], [1, 2, [3, 2]]));
Gopinath Shiva
4
@ GopinathShiva: Ya, itu hanya gagal jika Anda mengharapkannya kembali true. Jawabannya menjelaskan bahwa itu tidak akan terjadi. Jika Anda perlu membandingkan array bersarang, Anda dapat dengan mudah menambahkan cek rekursif.
Tim Down
59

Cara Praktis

Saya pikir itu salah untuk mengatakan implementasi tertentu adalah "The Right Way ™" jika itu hanya "benar" ("benar") berbeda dengan solusi "salah". Solusi Tomáš adalah peningkatan yang jelas atas perbandingan array berbasis string, tetapi itu tidak berarti itu secara objektif "benar". Apa yang benar ? Apakah ini yang tercepat? Apakah ini yang paling fleksibel? Apakah ini yang termudah untuk dipahami? Apakah ini cara tercepat untuk melakukan debug? Apakah itu menggunakan operasi paling sedikit? Apakah ada efek sampingnya? Tidak ada satu solusi yang dapat memiliki yang terbaik dari semua hal.

Tomáš dapat mengatakan solusinya cepat tetapi saya juga akan mengatakan itu tidak perlu rumit. Itu mencoba untuk menjadi solusi all-in-one yang bekerja untuk semua array, bersarang atau tidak. Bahkan, ia menerima lebih dari sekadar array sebagai input dan masih berusaha memberikan jawaban yang "valid".


Generik menawarkan usabilitas

Jawaban saya akan mendekati masalah secara berbeda. Saya akan mulai dengan arrayCompareprosedur generik yang hanya berkaitan dengan melangkah melalui array. Dari sana, kami akan membangun fungsi perbandingan dasar kami seperti arrayEqualdan arrayDeepEqual, dll

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

Menurut pendapat saya, jenis kode terbaik bahkan tidak perlu komentar, dan ini tidak terkecuali. Ada begitu sedikit yang terjadi di sini sehingga Anda dapat memahami perilaku prosedur ini dengan hampir tidak ada usaha sama sekali. Tentu, beberapa sintaks ES6 mungkin tampak asing bagi Anda sekarang, tetapi itu hanya karena ES6 relatif baru.

Seperti yang disarankan oleh tipe, arrayComparedibutuhkan fungsi perbandingan f,, dan dua larik input, xsdan ys. Untuk sebagian besar, yang kita lakukan hanyalah memanggil f (x) (y)untuk setiap elemen dalam array input. Kami mengembalikan lebih awal falsejika pengguna yang ditentukan fkembali false- berkat &&evaluasi hubung singkat. Jadi ya, ini berarti komparator dapat menghentikan iterasi lebih awal dan mencegah perulangan melalui sisa array input ketika tidak perlu.


Perbandingan yang ketat

Selanjutnya, menggunakan arrayComparefungsi kita, kita dapat dengan mudah membuat fungsi lain yang mungkin kita butuhkan. Kami akan mulai dengan 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

Sederhana seperti itu. arrayEqualdapat didefinisikan dengan arrayComparedan fungsi pembanding yang membandingkan adengan bmenggunakan ===(untuk kesetaraan yang ketat).

Perhatikan bahwa kami juga mendefinisikan equalfungsinya sendiri. Ini menyoroti peran arrayComparesebagai fungsi tingkat tinggi untuk memanfaatkan pembanding orde pertama kami dalam konteks tipe data lain (Array).


Perbandingan longgar

Kita bisa dengan mudah didefinisikan arrayLooseEqualmenggunakan ==gantinya. Sekarang ketika membandingkan 1(Nomor) ke '1'(String), hasilnya adalah 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

Perbandingan mendalam (rekursif)

Anda mungkin telah memperhatikan bahwa ini hanya perbandingan dangkal. Tentunya solusi Tomáš adalah "The Right Way ™" karena ia melakukan perbandingan mendalam secara implisit, bukan?

Nah arrayCompareprosedur kami cukup fleksibel untuk digunakan dengan cara yang membuat tes kesetaraan yang mendalam menjadi mudah ...

// 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

Sederhana seperti itu. Kami membangun komparator dalam menggunakan fungsi tingkat tinggi lainnya . Kali ini kami membungkus arrayComparemenggunakan pembanding khusus yang akan memeriksa apakah adan barray. Jika demikian, permohonan kembali arrayDeepComparemembandingkan adan bke pembanding yang ditentukan pengguna ( f). Ini memungkinkan kita untuk memisahkan perilaku perbandingan mendalam dari bagaimana kita benar-benar membandingkan unsur-unsur individu. Yaitu, seperti contoh di atas menunjukkan, kita bisa membandingkan menggunakan equal,looseEqual , atau pembanding lain yang kami buat.

Karena arrayDeepComparesudah dikeringkan, kita dapat menerapkannya sebagian seperti yang kita lakukan pada contoh sebelumnya juga

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

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

Bagi saya, ini sudah merupakan peningkatan yang jelas atas solusi Tomáš karena saya dapat secara eksplisit memilih perbandingan yang dangkal atau dalam untuk array saya, sesuai kebutuhan.


Perbandingan objek (contoh)

Sekarang bagaimana jika Anda memiliki array benda atau sesuatu? Mungkin Anda ingin menganggap array itu sebagai "sama" jika setiap objek memiliki nilai yang sama id...

// 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

Sederhana seperti itu. Di sini saya telah menggunakan objek vanilla JS, tetapi jenis pembanding ini dapat bekerja untuk semua jenis objek; bahkan objek khusus Anda. Solusi Tomáš perlu dikerjakan ulang sepenuhnya untuk mendukung tes kesetaraan semacam ini

Array dalam dengan objek? Bukan masalah. Kami membangun fungsi generik yang sangat fleksibel, sehingga mereka akan bekerja dalam berbagai macam kasus penggunaan.

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

Perbandingan sewenang-wenang (contoh)

Atau bagaimana jika Anda ingin melakukan semacam perbandingan yang sepenuhnya sewenang-wenang? Mungkin saya ingin tahu apakah masing x- masing lebih besar dari masing-masing 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

Kurang itu lebih

Anda dapat melihat kami sebenarnya melakukan lebih banyak dengan lebih sedikit kode. Tidak ada yang rumit tentang ituarrayCompare dirinya sendiri dan masing-masing pembanding khusus yang kami buat memiliki implementasi yang sangat sederhana.

Dengan mudah, kita dapat mendefinisikan persis bagaimana kita ingin untuk dua array untuk dibandingkan - dangkal, dalam, ketat, longgar, beberapa objek properti, atau beberapa perhitungan sewenang-wenang, atau kombinasi dari ini - semua menggunakan satu prosedur , arrayCompare. Mungkin bahkan bermimpi aRegExp pembanding! Saya tahu bagaimana anak-anak menyukai regexps itu ...

Apakah ini yang tercepat? Nggak. Tapi mungkin juga tidak perlu. Jika kecepatan adalah satu-satunya metrik yang digunakan untuk mengukur kualitas kode kami, banyak kode yang benar-benar hebat akan dibuang - Itulah sebabnya saya menyebut pendekatan ini dengan Cara Praktis . Atau mungkin lebih adil, Cara Praktis. Deskripsi ini cocok untuk jawaban ini karena saya tidak mengatakan jawaban ini hanya praktis dibandingkan dengan beberapa jawaban lainnya; itu benar secara objektif. Kami telah mencapai tingkat kepraktisan yang tinggi dengan kode yang sangat sedikit yang sangat mudah untuk dipikirkan. Tidak ada kode lain yang dapat mengatakan bahwa kami belum mendapatkan deskripsi ini.

Apakah itu menjadikannya solusi "tepat" untuk Anda? Terserah Anda yang memutuskan. Dan tidak ada orang lain yang bisa melakukannya untuk Anda; hanya Anda yang tahu apa kebutuhan Anda. Dalam hampir semua kasus, saya menghargai kode yang mudah, praktis, dan serbaguna daripada jenis yang pintar dan cepat. Apa yang Anda nilai mungkin berbeda, jadi pilihlah yang cocok untuk Anda.


Edit

Jawaban lama saya lebih fokus pada penguraian arrayEqualmenjadi prosedur kecil. Ini latihan yang menarik, tetapi bukan cara terbaik (paling praktis) untuk mendekati masalah ini. Jika Anda tertarik, Anda dapat melihat riwayat revisi ini.

Terima kasih
sumber
8
"jenis kode terbaik bahkan tidak memerlukan komentar" ... benci mengatakannya, tetapi kode ini dapat menggunakan lebih banyak komentar, dan / atau nama yang berbeda - "bandingkan" cukup kabur. Jika saya membaca dengan benar, "perbandingan" Anda pada dasarnya adalah rekursif kari "setiap". Kupikir. Atau apakah itu adalah "beberapa" rekursif kari? Hmm. Ini membutuhkan lebih banyak pemikiran daripada yang diperlukan. Mungkin nama yang lebih baik adalah "arraysEquivalent", memanfaatkan terminologi standar "hubungan ekivalensi". Atau, lebih jelas lagi (bagi saya), "recursivelyEquivalent".
Don Hatch
1
@ DonHatch terima kasih atas kesempatan untuk membalas. Maksud Anda dengan "membandingkan" arrayCompare? Ya fungsinya sudah dikeringkan, tetapi berbeda dari somedan every. arrayCompareDibutuhkan pembanding dan dua array untuk membandingkan. Saya memilih nama generik khusus karena kita dapat membandingkan array menggunakan fungsi sembarang. Fungsi ini dikerjakan sehingga dapat dikhususkan untuk membuat fungsi perbandingan array baru (misalnya, arrayEqual). Bisakah Anda menyarankan nama yang lebih baik? Area apa yang menurut Anda memerlukan komentar atau penjelasan tambahan? Saya senang mendiskusikan ^ _ ^
Terima kasih
1
Tidak yakin apakah poin saya jelas - tapi maksud saya adalah, fungsi Anda tidak benar-benar dimaksudkan untuk mengambil fungsi arbitrer , saya tidak berpikir - itu dimaksudkan untuk mengambil relasi ekivalensi , dan mengembalikan relasi ekivalensi. Itu penting - itu tidak akan melakukan sesuatu yang masuk akal (saya tidak berpikir) jika diberi beberapa jenis fungsi biner sewenang-wenang seperti yang saya sebutkan, bahkan yang sering orang sebut "bandingkan". Jadi saya pikir akan sangat membantu untuk menempatkan "setara" dalam nama di tempat "bandingkan".
Don Hatch
1
@ftor, penulis: jawaban super bermanfaat, kerja bagus, +1. Umpan balik: Anda menganjurkan kesederhanaan, namun tidak ada cara ekspresi dengan tiga panah pada satu baris sederhana atau mudah dipahami bagi banyak pengembang. Sebagai contoh: f => ([x, ... xs]) => ([y, ... ys]) =>. Saya terus-menerus menggunakan ini dan masih harus menguraikannya secara mental, daripada "hanya melihatnya". Titik kedua ftor benar, gunakan setiap. Bahkan menimbang alasan Anda, secara seimbang rasanya lebih baik tidak hanya bagi saya, tetapi juga dari sudut pandang Anda ketika mencoba menyimpulkan filosofi desain Anda.
whitneyland
1
Saya mengerti ini adalah tempat untuk belajar, tetapi saya membuat asumsi di sini bahwa rata-rata programmer yang mempelajari gaya fungsional dapat mengubah fungsi kari menjadi yang tidak terburu-buru. Jawaban saya tidak membuat saran bahwa gaya ini dimaksudkan untuk digunakan dalam program Anda sendiri - tulislah itu tidak terburu-buru, tulislah itu menggunakan aturan lekukan Anda sendiri, tulislah sesuai keinginan Anda - saya menulis jawaban saya dengan gaya yang saya percayai mengekspresikan program terbaik. Saya juga suka mengundang orang lain untuk menantang cara kami mengekspresikan program kami secara sintaksis
Terima kasih
54

Dalam semangat pertanyaan awal:

Saya ingin membandingkan dua array ... idealnya, efisien . Tidak ada yang mewah , hanya benar jika mereka identik, dan salah jika tidak.

Saya telah menjalankan tes kinerja pada beberapa saran yang lebih sederhana yang diusulkan di sini dengan hasil berikut (cepat ke lambat):

sementara (67%) oleh Tim Down

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

setiap (69%) oleh pengguna2782196

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

mengurangi (74%) oleh DEI

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

gabung & toString (78%) oleh Gaizka Allende & vivek

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

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

setengah toString (90%) oleh Victor Palomo

a1 == a2.toString();

stringify (100%) oleh radtek

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

Perhatikan contoh di bawah ini dengan asumsi bahwa array diurutkan, array satu dimensi. .lengthperbandingan telah dihapus untuk patokan umum (tambahkan a1.length === a2.lengthke salah satu saran dan Anda akan mendapatkan peningkatan kinerja ~ 10%) Pilih solusi apa pun yang paling sesuai untuk Anda mengetahui kecepatan dan keterbatasan masing-masing.

Catatan yang tidak terkait: menarik untuk melihat orang-orang mendapatkan semua pemicu-senang John Waynes pada tombol turun pada jawaban sah untuk pertanyaan ini.

unitario
sumber
Tautan membuka tes kosong.
Alexander Abakumov
Jika Anda menabrak ukuran array, angka-angka ini tidak berlaku (terutama pendekatan pengurangan). Coba dengan Array.from({length: 1000}).map((a,v)=> $ {v}.padStart(10,2));
Narayon
ini hanya berfungsi untuk array dangkal
Ramesh Rajendran
28

Membangun jawaban Tomáš Zato, saya setuju bahwa hanya mengulangi melalui array adalah yang tercepat. Selain itu (seperti yang telah dinyatakan orang lain), fungsi tersebut harus disebut sama dengan / sama, bukan membandingkan. Mengingat hal ini, saya memodifikasi fungsi untuk menangani membandingkan array untuk kesamaan - yaitu mereka memiliki elemen yang sama, tetapi tidak sesuai - untuk penggunaan pribadi, dan saya pikir saya akan melemparkannya ke sini untuk dilihat semua orang.

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

Fungsi ini mengambil parameter tambahan ketat yang standarnya menjadi true. Parameter ketat ini mendefinisikan jika array harus sepenuhnya sama di kedua konten dan urutan konten tersebut, atau hanya cukup berisi konten yang sama.

Contoh:

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

Saya juga menulis jsfiddle cepat dengan fungsi dan contoh ini:
http://jsfiddle.net/Roundaround/DLkxX/

Evan Steinkerchner
sumber
12

Meskipun ini memiliki banyak jawaban, salah satu yang saya yakin dapat membantu:

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

Tidak disebutkan dalam pertanyaan bagaimana struktur array akan terlihat seperti, jadi Jika Anda tahu pasti bahwa Anda tidak akan memiliki array bersarang atau objek dalam array Anda (itu terjadi pada saya, itu sebabnya saya datang ke ini jawab) kode di atas akan berfungsi.

Yang terjadi adalah kami menggunakan operator spread (...) untuk menggabungkan kedua array, lalu kami menggunakan Set untuk menghilangkan duplikat apa pun. Setelah Anda memilikinya, Anda dapat membandingkan ukurannya, jika ketiga array memiliki ukuran yang sama, Anda dapat melakukannya.

Jawaban ini juga mengabaikan urutan elemen , seperti yang saya katakan, situasi yang tepat terjadi pada saya, jadi mungkin seseorang dalam situasi yang sama mungkin berakhir di sini (seperti yang saya lakukan).


Edit1.

Menjawab pertanyaan Dmitry Grinko: "Mengapa Anda menggunakan operator spread (...) di sini - ... Perangkat baru? Tidak berfungsi"

Pertimbangkan kode ini:

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

Anda akan mendapatkannya

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

Agar dapat bekerja dengan nilai itu, Anda perlu menggunakan beberapa properti Set (lihat https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set ). Di sisi lain, ketika Anda menggunakan kode ini:

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

Anda akan mendapatkannya

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

Itulah bedanya, yang pertama akan memberi saya Set, itu akan bekerja juga karena saya bisa mendapatkan ukuran Set itu, tetapi yang terakhir memberi saya array yang saya butuhkan, apa yang lebih langsung ke resolusi.

Jeferson Euclides
sumber
Mengapa Anda menggunakan operator spread (...) di sini - ... Set baru? Itu tidak bekerja.
Dmitry Grinko
Dmitry Grinko Saya yakin saya menjawab pertanyaan Anda di Edit1 saya. Tapi saya tidak yakin apa yang Anda maksud dengan mengatakan 'itu tidak berhasil', karena kedua jawaban dapat menghalangi Anda
Jeferson Euclides
10

Pada baris yang sama dengan JSON.encode adalah menggunakan join ().

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

Satu-satunya masalah adalah jika Anda peduli tentang jenis yang diuji perbandingan terakhir. Jika Anda peduli tentang jenis, Anda harus mengulang.

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

Jika urutannya harus tetap sama, daripada hanya satu lingkaran, tidak ada jenis yang diperlukan.

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
epascarello
sumber
3
Ini hanya berfungsi untuk array tertentu, dan akan sangat lambat dengan array besar.
Tomáš Zato - Reinstate Monica
2
Membuat JSON juga berulang, Anda hanya (atau sepertinya begitu) tidak tahu tentang hal itu. Selain perulangan, menghasilkan JSON juga membutuhkan lebih banyak memori - ini menciptakan 2 representasi string dari array sebelum membandingkan. Fungsi downwote diimplementasikan untuk memesan jawaban dari yang terbaik ke yang terburuk. Saya pikir jawaban Anda bukanlah jawaban yang baik, jadi saya menurunkannya.
Tomáš Zato - Reinstate Monica
2
Maaf, saya hanya mengatakan JSON bukan .join(). Mungkin jika Anda menyatakan solusi kedua Anda sebagai yang utama (karena ini adalah solusi yang lebih baik, meskipun ompong terhadap array multidimensi), saya tidak akan menilai Anda seperti itu. Sejauh ini, saya menurunkan semua jawaban yang mengubah array menjadi string. Juga, saya memutakhirkan semua yang menggunakan cara yang benar, jika Anda perlu tahu itu. Ini berarti jawaban @Tim Down dan Bireys satu.
Tomáš Zato - Kembalikan Monica
6
GAGAL versi pertama:, checkArrays([1,2,3] , ["1,2",3]) == truedan sangat tidak mungkin itulah yang Anda inginkan terjadi!
Lakukan
2
@epascarello: Ya, Anda bisa tetapi (selain dari inefisiensi pemisah yang sangat panjang yang Anda sarankan) itu berarti akan ada kasus tepi (di mana array kebetulan berisi string dengan pemisah Anda di dalamnya) di mana fungsi checkArrays () bertingkah keliru . Ini mungkin tidak menjadi masalah jika Anda tahu sesuatu tentang isi array (sehingga Anda dapat memilih pemisah Anda yakin tidak akan ada dalam item array), tetapi jika Anda mencoba untuk menulis perbandingan array umum berfungsi, kemudian menggunakan join()seperti ini membuatnya buggy secara halus!
Lakukan
7

Berikut adalah versi naskah:

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

Beberapa test case untuk moka:

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)
})
Esqarrouth
sumber
6

Jika Anda menggunakan kerangka kerja pengujian seperti Mocha dengan pustaka pernyataan Chai , Anda bisa menggunakan kesetaraan yang mendalam untuk membandingkan array.

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

Ini harus mengembalikan true hanya jika array memiliki elemen yang sama di indeks yang sesuai.

metakermit
sumber
6

Jika hanya dua array angka atau string, ini adalah satu baris cepat

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
Gaizka Allende
sumber
const array1 = [1]; const array2 = [1, 1]; console.log (array1.join ('') === array2.join ('')) // mengembalikan true
Dan M.
seharusnya tidak: array1.join ('') adalah '1' dan array2.join ('') adalah '11'
Gaizka Allende
maaf, salah ketik. Array pertama seharusnya [11]. Cukup jelas mengapa ini terjadi dan bagaimana cara memperbaikinya.
Dan M.
Tidak yakin dengan apa yang Anda bicarakan, itu cukup sederhana: [1] .join () adalah "1" dan [1,1] .join () adalah "1,1", jadi mereka tidak akan pernah sama
Gaizka Allende
tolong, baca komentar saya lagi dengan lebih hati-hati. Jika Anda masih tidak melihatnya, silakan ambil jarahan di ideone.com/KFu427
Dan M.
5

Dalam kasus saya, array yang dibandingkan hanya berisi angka dan string. Fungsi ini akan menunjukkan kepada Anda jika array mengandung elemen yang sama.

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

Ayo kita coba!

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
yesnik
sumber
Pertanyaannya tidak meminta Anda untuk menyortir, jadi solusi Anda salah untuk contoh-contoh seperti are_arrs_equal([1,2], [2,1]). Juga, lihat diskusi lain di halaman ini untuk alasan pengerasan tidak perlu, rapuh, dan salah.
perlakukan mod Anda dengan baik
are_arrs_equal([1,2], [2,1])kembali trueseperti yang diharapkan. Mungkin solusi ini tidak ideal, tetapi berhasil untuk saya.
yesnik
Justru masalahnya, keduanya tidak sama dalam arti waras kata "sama" untuk struktur data yang diurutkan . Mereka adalah array, bukan set, dan jika Anda ingin menetapkan kesetaraan, Anda harus menyebutnya begitu - dan menjawab pertanyaan yang berbeda. :-)
perlakukan mod Anda dengan baik
1
Saya setuju dengan komentar di atas, tetapi solusi ini juga berfungsi untuk saya dalam array sederhana bilangan bulat saya, di mana pesanan tidak penting, jadi saya akan menggunakannya.
tomazahlin
1
Gagal untuk are_arrs_match([1,2], ["1,2"])(pengembalian true). Dan perhatikan bahwa the sort()panggilan akan mengubah array input - ini mungkin tidak diinginkan.
coba-tangkap-akhirnya
5

Ini membandingkan 2 array yang tidak disortir:

function areEqual(a, b) {
  if ( a.length != b.length) {
    return false;
  }
  return a.filter(function(i) {
    return !b.includes(i);
  }).length === 0;  
}
Nathan Boolean Trujillo
sumber
Meskipun mahal (dalam hal sumber daya komputasi), ini adalah solusi yang kuat yang harus baik untuk berbagai jenis, dan tidak bergantung pada penyortiran!
user3.1415927
5

Untuk sejumlah angka coba:

a1==''+a2

Catatan: metode ini tidak akan berfungsi ketika array juga mengandung string, mis a2 = [1, "2,3"].

Kamil Kiełczewski
sumber
trik pintar ..
javadba
4

Kita bisa melakukan ini dengan cara fungsional, menggunakan every( https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/every )

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
peonikel
sumber
4

Kode Anda tidak akan menangani kasus dengan tepat ketika kedua array memiliki elemen yang sama tetapi tidak dalam urutan yang sama.

Lihat kode saya dengan contoh Anda yang membandingkan dua array yang elemen-elemennya adalah angka, Anda dapat memodifikasi atau memperluasnya untuk tipe elemen lainnya (dengan memanfaatkan .join () alih-alih .toString ()).

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

durga patra
sumber
3

Inilah solusi saya:

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

Bekerja dengan struktur data bersarang, dan jelas mengabaikan metode objek. Jangan pernah berpikir untuk memperluas Object.prototype dengan metode ini, ketika saya mencoba ini sekali, jQuery rusak;)

Untuk sebagian besar array masih lebih cepat daripada sebagian besar solusi serialisasi. Ini mungkin metode perbandingan tercepat untuk array dari catatan objek.

Harry
sumber
tidak baik! ini memberi benar: equal({}, {a:1})dan equal({}, null)dan kesalahan ini keluar:equal({a:2}, null)
kristianlm
3
JSON.stringify(collectionNames).includes(JSON.stringify(sourceNames)) ?  array.push(collection[i]) : null

Beginilah cara saya melakukannya.

Leed
sumber
Solusi yang bagus - tetapi saya bertanya-tanya dalam situasi tertentu apakah itu tidak akan selalu berfungsi sebagaimana dimaksud, seperti dengan primitif tertentu atau array yang sangat bersarang? Saya harap ini bekerja dalam segala situasi
Ben Rondeau
3

Membandingkan 2 array:

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

fungsi panggilan

var isBool = compare(arr1.sort().join(),arr2.sort().join());
Amay Kulkarni
sumber
Jawaban ini tidak berfungsi, karena === tidak berlaku seperti yang diharapkan untuk array.
Michael Yang
Jawabannya berfungsi, meskipun === tidak memiliki arti apa pun di sini (karena sort () hanya bekerja pada array). Bahkan == juga akan berfungsi.
Amay Kulkarni
Cobalah sendiri; itu mencetak false jika Anda menjalankan kode ini. Ini karena perbandingan nilai referensi array dengan == dan === alih-alih nilai aktualnya. == dan === dimaksudkan hanya untuk perbandingan tipe primitif.
Michael Yang
Ini mengembalikan benar, kami telah menggunakannya, tetapi saya telah menghapus '===' sekarang karena tidak perlu
Amay Kulkarni
Ah, saya tidak melihat Anda mengkonversi ke string dan memanggil fungsi setelah memilah dan bergabung; Permintaan maafku.
Michael Yang
3

Saya percaya pada polos JSdan dengan ECMAScript 2015, yang manis dan mudah dimengerti.

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

}

berharap itu akan membantu seseorang.

ArifMustafa
sumber
1
Mengapa cek sebaliknya diperlukan? Kita tahu array memiliki ukuran yang sama, jadi jika setiap item dalam array1 juga ditemukan di array2; mengapa kita kemudian harus memeriksa bahwa setiap item dalam array2 juga ada di array1?
JeffryHouser
2

Memperluas ide Tomáš Zato. Tomas's Array.prototype.compare harus benar disebut Array.prototype.compareIdentical.

Itu lewat:

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

Tetapi gagal pada:

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

Berikut ini versi yang lebih baik (menurut saya):

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/

Igor S.
sumber
2
-1. Jika 'gagal' pada contoh yang Anda berikan, maka itu hanya berlaku untuk definisi 'gagal' yang agak arbitrer. Mengapa Anda berharap dua array yang berbeda itu dianggap sama? Anda bahkan belum menjelaskan konsep 'kesetaraan' apa yang Anda coba terapkan di sini, atau mengapa itu masuk akal atau membantu, tetapi sepertinya Anda ingin array multidimensi dibandingkan seolah-olah mereka runtuh menjadi satu dimensi. yang Jika demikian, Anda bahkan tidak mencapai itu: [1,2] .compare ([[1,2]]) memberikan false dengan versi Anda, seperti halnya dengan Tomáš.
Mark Amery
Berdasarkan apa yang saya dapat simpulkan, ia mengatakan bahwa [1, 2, 3, 4] dan [1, 3, 2, 4] harus dibandingkan dengan yang setara (Orde tidak penting).
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);

////// ATAU ///////

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)
Vasanth
sumber
Anda dapat Anda beberapa fungsi juga yang tidak akan sepenuhnya beralih jika kita mendapatkan kondisi yang diperlukan terpenuhi, seperti di atas
Vasanth
2

Pendekatan lain dengan kode sangat sedikit (menggunakan pengurangan Array dan mencakup Array ):

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

Jika Anda ingin membandingkan juga kesetaraan pesanan:

arr1.length == arr2.length && arr1.reduce((a, b, i) => a && arr2[i], true)
  • The lengthcek memastikan bahwa set elemen dalam satu array bukan hanya bagian dari yang lain.

  • Peredam digunakan untuk berjalan melalui satu array dan mencari setiap item dalam array lain. Jika satu item tidak ditemukan, pengurangan fungsi akan kembali false.

    1. Dalam contoh pertama sedang diuji bahwa suatu elemen disertakan
    2. Contoh kedua memeriksa pesanan juga
Sayang
sumber
1
dapatkah Anda menjelaskan sedikit kode Anda untuk membuat jawaban ini lebih jelas?
ted
1. bandingkan panjang array untuk memastikan bahwa satu array bukan subset dari yang lainnya
DEls
2. Gunakan peredam untuk berjalan melalui satu array dan mencari setiap item dalam array lain. Jika satu item tidak ditemukan, fungsi pengurangan mengembalikan 'false'
DEls
@DEls: mengedit penjelasan Anda menjadi jawaban (sedikit ditulis ulang dan diperluas). Anda sekarang dapat menghapus komentar Anda dan menandai komentar pertama dan yang ini sudah usang.
coba-tangkap-akhirnya
2

Pendekatan sederhana:

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;
}
Pedro Rodrigues
sumber
2

Sudah beberapa jawaban yang bagus. Tetapi saya ingin berbagi ide anter yang telah terbukti andal dalam membandingkan array. Kita dapat membandingkan dua array menggunakan JSON.stringify () . Ini akan membuat string keluar dari array dan dengan demikian membandingkan dua string yang diperoleh dari dua array untuk kesetaraan

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
AL-zami
sumber
2

Rekursif & bekerja pada array NESTED :

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"]]]
));;  
JMI MADISON
sumber
2

Bekerja dengan argumen MULTIPLE dengan array NESTED :

//: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"   ]]],
));; 
JMI MADISON
sumber
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  
Pedro Bustamante
sumber