Apakah ada cara untuk mengembalikan perbedaan antara dua array dalam JavaScript?
Sebagai contoh:
var a1 = ['a', 'b'];
var a2 = ['a', 'b', 'c', 'd'];
// need ["c", "d"]
javascript
arrays
array-difference
John Adawan
sumber
sumber
O(a1.length x log(a2.length))
- apakah kinerja ini dimungkinkan dalam JavaScript?Jawaban:
Saya berasumsi Anda membandingkan array normal. Jika tidak, Anda perlu mengubah untuk loop untuk sebuah untuk .. di lingkaran.
Solusi yang lebih baik, jika Anda tidak peduli tentang kompatibilitas ke belakang, menggunakan filter. Namun tetap saja, solusi ini berhasil.
sumber
var a1 = ['a', 'b'];
danvar a2 = ['a', 'b', 'c', 'd', 'b'];
, itu akan mengembalikan jawaban yang salah , yaitu['c', 'd', 'b']
bukannya['c', 'd']
.function diff2(a, b) { var i, la = a.length, lb = b.length, res = []; if (!la) return b; else if (!lb) return a; for (i = 0; i < la; i++) { if (b.indexOf(a[i]) === -1) res.push(a[i]); } for (i = 0; i < lb; i++) { if (a.indexOf(b[i]) === -1) res.push(b[i]); } return res; }
Ada cara yang lebih baik menggunakan ES7:
Persimpangan
Untuk
[1,2,3] [2,3]
itu akan menghasilkan[2,3]
. Di sisi lain, karena[1,2,3] [2,3,5]
akan mengembalikan hal yang sama.Perbedaan
Untuk
[1,2,3] [2,3]
itu akan menghasilkan[1]
. Di sisi lain, karena[1,2,3] [2,3,5]
akan mengembalikan hal yang sama.Untuk perbedaan simetris , Anda dapat melakukan:
Dengan cara ini, Anda akan mendapatkan array yang berisi semua elemen arr1 yang tidak ada di arr2 dan sebaliknya
Seperti @Joshaven Potter menunjukkan jawabannya, Anda dapat menambahkan ini ke Array.prototype sehingga dapat digunakan seperti ini:
sumber
< 0
daripada== -1
Array
perbedaannya disebutset operation
, karena pencarian properti adalah pekerjaanSet
s sendiri, yang urutan besarnya lebih cepat dariindexOf
/includes
. Sederhananya, solusi Anda sangat tidak efisien dan agak lambat.Set
, nilai harus unik, bukan?[1,2,3] [2,3,5]
angka-angkanya unik tetapi jika Anda mengatakan[1,1,2,3] [1,2,3,5]
dan berharap[1]
Anda tidak dapat menggunakannyaSet
. Solusi Anda tidak akan bekerja: - / Saya akhirnya membuat fungsi ini karena saya tidak bisa menemukan cara yang memuaskan untuk melakukannya dengan lebih ringkas. Jika Anda memiliki ide tentang cara melakukan itu, saya ingin tahu!Array.includes()
fitur ES7 bukan ES6? (1) (2) - dan untuk melanjutkan, dengan ES6 Anda dapat menggunakanArray.some()
misalnyalet intersection = aArray.filter(a => bArray.some(b => a === b))
, bukan?Tampilkan cuplikan kode
Catatan indexOf dan filter tidak tersedia di ie sebelum ie9.
sumber
[1,2,3].diff([3,4,5])
ia akan kembali[1,2]
sebagai ganti[1,2,4,5]
sehingga tidak menyelesaikan masalah di pertanyaan awal, sesuatu yang harus diperhatikan.Sejauh ini, ini adalah cara termudah untuk mendapatkan hasil yang Anda cari, menggunakan jQuery:
diff
sekarang berisi apa yang ada di dalamnyaold_array
yang tidak ada dinew_array
sumber
{a: 1} != {a: 1}
) ( bukti ).not
array, jQuery menggunakan utilitas bawaannya.grep()
yang khusus untuk memfilter array. Saya tidak bisa melihat perubahan ini.Metode perbedaan di Underscore (atau penggantian drop-in, Lo-Dash ) dapat melakukan ini juga:
Seperti halnya fungsi Garis Bawah, Anda juga bisa menggunakannya dalam gaya yang lebih berorientasi objek:
sumber
JavaScript polos
Ada dua kemungkinan intepretasi untuk "perbedaan". Saya akan membiarkan Anda memilih yang mana yang Anda inginkan. Katakanlah Anda memiliki:
Jika Anda ingin mendapatkan
['a']
, gunakan fungsi ini:Jika Anda ingin mendapatkan
['a', 'c']
(semua elemen yang terkandung dalam salah satua1
ataua2
, tetapi tidak keduanya - yang disebut perbedaan simetris ), gunakan fungsi ini:Lodash / Garis Bawah
Jika Anda menggunakan lodash, Anda dapat menggunakan
_.difference(a1, a2)
(kasus 1 di atas) atau_.xor(a1, a2)
(kasus 2).Jika Anda menggunakan Underscore.js, Anda dapat menggunakan
_.difference(a1, a2)
fungsi untuk case 1.ES6 Set, untuk array yang sangat besar
Kode di atas berfungsi di semua browser. Namun, untuk array besar lebih dari sekitar 10.000 item, itu menjadi sangat lambat, karena memiliki kompleksitas O (n²). Pada banyak browser modern, kita dapat memanfaatkan
Set
objek ES6 untuk mempercepatnya. Lodash secara otomatis digunakanSet
ketika tersedia. Jika Anda tidak menggunakan lodash, gunakan implementasi berikut, yang terinspirasi oleh posting blog Axel Rauschmayer :Catatan
Perilaku untuk semua contoh mungkin mengejutkan atau tidak jelas jika Anda peduli dengan -0, +0, NaN atau array jarang. (Untuk sebagian besar kegunaan, ini tidak masalah.)
sumber
Untuk mendapatkan perbedaan simetris Anda perlu membandingkan array dalam kedua cara (atau dalam semua cara dalam kasus beberapa array)
ES7 (ECMAScript 2016)
ES6 (ECMAScript 2015)
ES5 (ECMAScript 5.1)
Contoh:
Perbedaan antara Array Objek
Contoh:
sumber
Pendekatan yang lebih bersih dalam ES6 adalah solusi berikut.
Perbedaan
Persimpangan
Disjunctive Union (Perbedaan Simetris)
sumber
a1 = ['a', 'b', 'e']
: e tidak akan diekstraksi.Anda dapat menggunakan Set dalam kasus ini. Ini dioptimalkan untuk jenis operasi ini (penyatuan, persimpangan, perbedaan).
Pastikan itu berlaku untuk kasus Anda, setelah tidak ada duplikat.
sumber
Set
fungsi tanpa harus mendapatkan yang lain ...Gabungkan kedua array, nilai unik hanya akan muncul sekali sehingga indexOf () akan sama dengan lastIndexOf ().
sumber
untuk mengurangi satu array dari yang lain, cukup gunakan snippet di bawah ini:
Ini akan mengembalikan ['1,' 2 ',' 6 '] yang merupakan item dari larik pertama yang tidak ada di larik kedua.
Oleh karena itu, sesuai dengan sampel masalah Anda, kode berikut adalah solusi yang tepat:
sumber
Dengan kedatangan ES6 dengan set dan operator percikan (pada saat itu hanya berfungsi di Firefox, periksa tabel kompatibilitas ), Anda dapat menulis satu liner berikut:
yang akan menghasilkan
[ "c", "d" ]
.sumber
b.filter(x => !a.indexOf(x)))
O(n + m)
Anda diO(n * m)
mana n dan m adalah panjang array. Buat daftar panjang dan solusi saya akan berjalan dalam hitungan detik, sedangkan milik Anda akan memakan waktu berjam-jam.a.filter(x => !b1.has(x))
lebih sederhana. Dan perhatikan spec hanya membutuhkan kompleksitas yang akann * f(m) + m
denganf(m)
sublinear rata-rata. Ini lebih baik daripadan * m
, tetapi tidak harusn + m
.var difference = [...new Set([...a].filter(x => !b1.has(x)))];
Mengapa Anda membuat duplikat array 'a'? Mengapa Anda mengubah hasil filter menjadi satu set dan kemudian kembali ke array? Bukankah ini setara denganvar difference = a.filter(x => !b1.has(x));
Pendekatan fungsional dengan ES2015
Komputasi
difference
antara dua array adalah salah satuSet
operasi. Istilah sudah menunjukkan bahwaSet
jenis asli harus digunakan, untuk meningkatkan kecepatan pencarian. Bagaimanapun, ada tiga permutasi ketika Anda menghitung perbedaan antara dua set:Berikut adalah solusi fungsional yang mencerminkan permutasi ini.
Kiri
difference
:Benar
difference
:differencer
sepele. Itu hanyadifferencel
dengan argumen terbalik. Anda dapat menulis fungsi untuk kenyamanan:const differencer = flip(differencel)
. Itu saja!Simetris
difference
:Sekarang kita memiliki yang kiri dan kanan, mengimplementasikan simetris
difference
menjadi sepele juga:Saya kira contoh ini adalah titik awal yang baik untuk mendapatkan kesan apa arti pemrograman fungsional:
Pemrograman dengan blok bangunan yang dapat dihubungkan bersama dengan berbagai cara.
sumber
Solusi menggunakan
indexOf()
akan baik untuk array kecil tetapi karena mereka tumbuh panjang kinerja pendekatan algoritmaO(n^2)
. Berikut adalah solusi yang akan bekerja lebih baik untuk array yang sangat besar dengan menggunakan objek sebagai array asosiatif untuk menyimpan entri array sebagai kunci; itu juga menghilangkan entri duplikat secara otomatis tetapi hanya berfungsi dengan nilai string (atau nilai yang dapat disimpan dengan aman sebagai string):sumber
Jawaban di atas oleh Joshaven Potter luar biasa. Tetapi mengembalikan elemen dalam array B yang tidak dalam array C, tetapi tidak sebaliknya. Misalnya, jika
var a=[1,2,3,4,5,6].diff( [3,4,5,7]);
kemudian akan menampilkan: ==>[1,2,6]
, tetapi tidak[1,2,6,7]
, yang merupakan perbedaan aktual antara keduanya. Anda masih dapat menggunakan kode Potter di atas tetapi cukup ulangi perbandingannya sekali lagi juga:Ini akan menghasilkan:
[ 1, 2, 6, 7 ]
sumber
Cara lain untuk memecahkan masalah
Anda juga dapat menggunakan sintaks fungsi panah:
sumber
sumber
difference
sebagai fungsi di versi masa depan dan fungsi ini kemudian memiliki fungsi tanda tangan yang berbeda dari Anda, itu akan merusak kode Anda atau pustaka asing yang menggunakan fungsi ini.Solusi Sangat Sederhana dengan fungsi filter JavaScript:
sumber
Bagaimana dengan ini:
Jadi cara ini dapat Anda lakukan
array1.diff(array2)
untuk mendapatkan perbedaannya (kompleksitas waktu yang mengerikan untuk algoritma - O (array1.length x array2.length) Saya percaya)sumber
Menggunakan http://phrogz.net/JS/ArraySetMath.js Anda dapat:
sumber
ini bekerja untuk saya
sumber
filter
)fn
Parameter panggilan balik opsional yang memungkinkan Anda menentukan cara membandingkan item arraysumber
length
nilai. Ini sudah properti biasa. jsperf.com/array-length-cachingIni berfungsi: pada dasarnya menggabungkan dua array, mencari duplikat dan mendorong apa yang tidak digandakan ke array baru yang merupakan perbedaan.
sumber
// pendekatan es6
sumber
Kompleksitas simetris dan linier . Membutuhkan ES6.
sumber
Belum jawaban lain, tetapi tampaknya tidak ada yang menyebutkan jsperf di mana mereka membandingkan beberapa algoritma dan dukungan teknologi: https://jsperf.com/array-difference-javascript tampaknya menggunakan filter mendapatkan hasil terbaik. Terima kasih
sumber
Hanya berpikir ... demi tantangan ;-) akankah ini berhasil ... (untuk array dasar string, angka, dll.) Tidak ada array bersarang
Perhatikan pengurutan kemungkinan tidak akan seperti yang disebutkan di atas ... tetapi jika diinginkan, panggil .sort () pada array untuk mengurutkannya.
sumber
Saya ingin fungsi serupa yang mengambil array lama dan array baru dan memberi saya array item yang ditambahkan dan array item yang dihapus, dan saya ingin itu menjadi efisien (jadi tidak ada .contains!).
Anda dapat bermain dengan solusi yang saya usulkan di sini: http://jsbin.com/osewu3/12 .
Adakah yang bisa melihat masalah / peningkatan pada algoritma itu? Terima kasih!
Daftar kode:
sumber
Saya mencari jawaban sederhana yang tidak melibatkan menggunakan perpustakaan yang berbeda, dan saya datang dengan saya sendiri yang saya pikir tidak disebutkan di sini. Saya tidak tahu seberapa efisien itu atau apa pun selain itu berfungsi;
Untuk kode saya, saya perlu duplikat juga diambil, tapi saya kira itu tidak selalu disukai.
Saya kira downside utama adalah itu berpotensi membandingkan banyak opsi yang sudah ditolak.
sumber
littlebit memperbaiki untuk jawaban terbaik
ini akan mempertimbangkan jenis elemen saat ini. b / c ketika kita membuat [a1 [i]] itu mengkonversi nilai menjadi string dari nilai aslinya, jadi kami kehilangan nilai aktual.
sumber