Cara menggabungkan dua array dalam JavaScript dan menghapus duplikat item


1368

Saya punya dua array JavaScript:

var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];

Saya ingin hasilnya:

var array3 = ["Vijendra","Singh","Shakya"];

Keluaran array seharusnya kata-kata yang berulang dihapus.

Bagaimana cara menggabungkan dua array dalam JavaScript sehingga saya hanya mendapatkan item unik dari setiap array dalam urutan yang sama ketika mereka dimasukkan ke dalam array asli?


1
Sebelum Anda memposting jawaban baru, pertimbangkan sudah ada 75+ jawaban untuk pertanyaan ini. Harap pastikan bahwa jawaban Anda menyumbangkan informasi yang tidak ada di antara jawaban yang ada.
janniks

[... Set baru ([... [1, 2, 3], ... [2, 3, 4]])]]] [] 1, 2, 3, 4]
Denis Giffeler

Jika Anda menginginkan solusi yang lebih umum yang juga mencakup penggabungan yang mendalam, lihat pertanyaan ini . Beberapa jawaban juga mencakup array.
Martin Braun

Jawaban:


1667

Untuk hanya menggabungkan array (tanpa menghapus duplikat)

Penggunaan versi ES5 Array.concat:

var array1 = ["Vijendra", "Singh"];
var array2 = ["Singh", "Shakya"];

console.log(array1.concat(array2));

Versi ES6 menggunakan destrukturisasi

const array1 = ["Vijendra","Singh"];
const array2 = ["Singh", "Shakya"];
const array3 = [...array1, ...array2];

Karena tidak ada cara 'bawaan' untuk menghapus duplikat ( ECMA-262 sebenarnya memiliki Array.forEachyang akan bagus untuk ini), kita harus melakukannya secara manual:

Array.prototype.unique = function() {
    var a = this.concat();
    for(var i=0; i<a.length; ++i) {
        for(var j=i+1; j<a.length; ++j) {
            if(a[i] === a[j])
                a.splice(j--, 1);
        }
    }

    return a;
};

Kemudian, untuk menggunakannya:

var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];
// Merges both arrays and gets unique items
var array3 = array1.concat(array2).unique(); 

Ini juga akan mempertahankan urutan array (yaitu, tidak diperlukan penyortiran).

Karena banyak orang merasa terganggu dengan augmentasi Array.prototypedan for inloop prototipe , berikut ini cara yang kurang invasif untuk menggunakannya:

function arrayUnique(array) {
    var a = array.concat();
    for(var i=0; i<a.length; ++i) {
        for(var j=i+1; j<a.length; ++j) {
            if(a[i] === a[j])
                a.splice(j--, 1);
        }
    }

    return a;
}

var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];
    // Merges both arrays and gets unique items
var array3 = arrayUnique(array1.concat(array2));

Bagi mereka yang cukup beruntung untuk bekerja dengan browser di mana ES5 tersedia, Anda dapat menggunakan Object.definePropertyseperti ini:

Object.defineProperty(Array.prototype, 'unique', {
    enumerable: false,
    configurable: false,
    writable: false,
    value: function() {
        var a = this.concat();
        for(var i=0; i<a.length; ++i) {
            for(var j=i+1; j<a.length; ++j) {
                if(a[i] === a[j])
                    a.splice(j--, 1);
            }
        }

        return a;
    }
});

281
Perhatikan bahwa algoritma ini adalah O (n ^ 2).
Gumbo

7
Biarkan [a, b, c]dan [x, b, d]jadilah array (anggap kutipan). Concat memberi [a, b, c, x, b, d]. Bukankah keluaran unik () menjadi [a, c, x, b, d]. Itu tidak menjaga urutan saya pikir - Saya percaya OP ingin[a, b, c, x, d]
Amarghosh

89
OP menerima jawaban pertama yang membuatnya bekerja dan menandatanganinya. Kami masih membandingkan solusi satu sama lain, mencari-n-memperbaiki kesalahan, meningkatkan kinerja, memastikan yang kompatibel di mana-mana dan seterusnya ... Keindahan stackoverflow :-)
Amarghosh

6
Saya awalnya memilih ini tetapi telah berubah pikiran. Menetapkan prototipe ke Array.prototype memiliki konsekuensi melanggar pernyataan "untuk ... dalam". Jadi solusi terbaik mungkin menggunakan fungsi seperti ini tetapi tidak menetapkannya sebagai prototipe. Beberapa orang mungkin berpendapat bahwa pernyataan "untuk ..." tidak boleh digunakan untuk mengulangi elemen array, tetapi orang sering menggunakannya seperti itu sehingga setidaknya solusi ini digunakan dengan hati-hati.
Code Commander

16
Anda harus selalu menggunakan for ... indengan hasOwnPropertydalam hal metode prototype baik-baik saja
mulllhausen

600

Dengan Underscore.js atau Lo-Dash Anda dapat melakukannya:

console.log(_.union([1, 2, 3], [101, 2, 1, 10], [2, 1]));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>

http://underscorejs.org/#union

http://lodash.com/docs#union


70
Atau, mungkin bahkan lebih baik daripada garis bawah, lodash yang kompatibel dengan API .
Brian M. Hunt

3
@ Ygg Dari dokumen lodash. "Mengembalikan array nilai unik yang baru, secara berurutan , yang ada di satu atau lebih dari array."
Richard Ayotte

4
Saya lebih suka underscore.js. Apa yang akhirnya saya gunakan adalah underscore.flatten(), yang lebih baik daripada penyatuan karena dibutuhkan array array.
penenun

8
@ weaver _.flatten bergabung, tetapi tidak 'menghapus duplikat'.
GijsjanB

9
Performa cepat menghadapi lodash vs jawaban teratas: jsperf.com/merge-two-arrays-keeping-only-unique-values
slickplaid

288

Pertama menggabungkan dua array, berikutnya hanya menyaring item unik:

var a = [1, 2, 3], b = [101, 2, 1, 10]
var c = a.concat(b)
var d = c.filter((item, pos) => c.indexOf(item) === pos)

console.log(d) // d is [1, 2, 3, 101, 10]

Edit

Seperti yang disarankan, solusi yang lebih berkinerja baik adalah menyaring item-item unik bsebelum bergabung dengan a:

var a = [1, 2, 3], b = [101, 2, 1, 10]
var c = a.concat(b.filter((item) => a.indexOf(item) < 0))

console.log(c) // c is [1, 2, 3, 101, 10]


5
Solusi asli di sini memiliki manfaat menghapus dupes dalam setiap larik sumber. Saya kira itu tergantung pada konteks Anda yang akan Anda gunakan.
theGecko

Anda dapat menggabungkan yang berbeda untuk dukungan IE6: c = Array.from (Set baru (c));
Tobi G.

Jika saya ingin benar-benar berubah auntuk menambahkan b, apakah lebih baik untuk mengulang dan menggunakan push? a.forEach(function(item){ if(a.indexOf(item)<0) a.push(item); });
awe

1
Hanya pengingat penggunaan browser saat ini caniuse.com/usage-table untuk orang-orang yang cemas tentang IE6.
pmrotule

10
@Andrew: Bahkan lebih baik: 1. var c = [...a, ...b.filter(o => !~a.indexOf(o))]; 2. var c = [...new Set([...a, ...b])];
7vujy0f0hy

203

Ini adalah solusi ECMAScript 6 menggunakan spread operator dan array generics.

Saat ini hanya berfungsi dengan Firefox, dan mungkin Pratinjau Teknis Internet Explorer.

Tetapi jika Anda menggunakan Babel , Anda dapat memilikinya sekarang.

const input = [
  [1, 2, 3],
  [101, 2, 1, 10],
  [2, 1]
];
const mergeDedupe = (arr) => {
  return [...new Set([].concat(...arr))];
}

console.log('output', mergeDedupe(input));


14
Ini harus ditambahkan ke jawaban yang diterima. Solusi ini jauh lebih efisien dan jauh lebih elegan daripada apa yang saat ini mungkin tetapi itulah yang pasti akan dapat kita lakukan (dan harus dilakukan untuk mengikuti bidang ini).
EmmaGamma

Ini bukan quiiite sama dengan pertanyaan OP (ini tampaknya lebih dari sebuah peta datar daripada apa pun) tetapi upvote karena itu mengagumkan.
jedd.ahyoung

4
Sulit untuk mengatakan bahwa ini harus menjadi jawaban yang diterima karena pertanyaannya adalah dari 2009. Tapi ya, ini tidak hanya lebih "berkinerja" tetapi juga "elegan"
Cezar Augusto

11
Array.fromdapat digunakan sebagai ganti spread operator: Array.from(new Set([].concat(...arr)))
Henry Blyth

1
Ini sangat elegan. Sayangnya, ScriptScript belum mendukung ini. stackoverflow.com/questions/33464504/…
Ben Carp

190

ES6

array1.push(...array2) // => don't remove duplication 

ATAU

[...array1,...array2] //   =>  don't remove duplication 

ATAU

[...new Set([...array1 ,...array2])]; //   => remove duplication

1
Contoh 1/2 unionsama sekali tidak + Contoh 1 meledakkan tumpukan untuk Arrays besar + contoh 3 sangat lambat dan menghabiskan banyak memori, karena dua perantara Arrayharus dibangun + contoh 3 hanya dapat digunakan untuk uniondengan yang diketahui jumlah Arrays pada waktu kompilasi.

jadi bagaimana Anda akan melakukannya?
David Noreña

14
Setadalah cara untuk pergi ke sini
philk

3
Perhatikan bahwa untuk set tidak dapat menduplikat dua objek yang memiliki pasangan nilai kunci yang sama kecuali mereka adalah referensi objek yang sama.
Jun711

2
Tidak berfungsi dengan array objek, karena hanya akan menggabungkan referensi objek dan tidak peduli jika objek itu sendiri sama.
Wilson Biggs

87

Menggunakan Set (ECMAScript 2015), maka akan sesederhana itu:

const array1 = ["Vijendra", "Singh"];
const array2 = ["Singh", "Shakya"];
console.log(Array.from(new Set(array1.concat(array2))));


7
Saya menganggap ini sebagai "Jawaban yang Diterima" untuk menggunakan ES6.
mwieczorek

9
@mwieczorek Bagaimana:const array3 = [...new Set(array1.concat(array2))]
Robby Cornelissen

5
Tidak berfungsi jika Anda menggunakan Array objek
carkod

1
untuk menggabungkan objek yang berbeda tanpa menduplikasi: stackoverflow.com/a/54134237/3131433
Rakibul Haq

38

Ini adalah pandangan yang sedikit berbeda pada loop. Dengan beberapa optimasi dalam versi terbaru Chrome, ini adalah metode tercepat untuk menyelesaikan penyatuan dua array (Chrome 38.0.2111).

http://jsperf.com/merge-two-arrays-keeping-only-unique-values

var array1 = ["Vijendra", "Singh"];
var array2 = ["Singh", "Shakya"];
var array3 = [];

var arr = array1.concat(array2),
  len = arr.length;

while (len--) {
  var itm = arr[len];
  if (array3.indexOf(itm) === -1) {
    array3.unshift(itm);
  }
}

sementara loop: ~ 589k ops / s
filter: ~ 445k ops / s
lodash: 308k ops / s
untuk loop: 225k ops / s

Sebuah komentar menunjukkan bahwa salah satu variabel setup saya menyebabkan loop saya untuk menarik sisanya, karena tidak perlu menginisialisasi array kosong untuk menulis. Saya setuju dengan itu, jadi saya menulis ulang tes bahkan untuk bidang bermain, dan termasuk pilihan yang lebih cepat.

http://jsperf.com/merge-two-arrays-keeping-only-unique-values/52

let whileLoopAlt = function (array1, array2) {
    const array3 = array1.slice(0);
    let len1 = array1.length;
    let len2 = array2.length;
    const assoc = {};

    while (len1--) {
        assoc[array1[len1]] = null;
    }

    while (len2--) {
        let itm = array2[len2];

        if (assoc[itm] === undefined) { // Eliminate the indexOf call
            array3.push(itm);
            assoc[itm] = null;
        }
    }

    return array3;
};

Dalam solusi alternatif ini, saya telah menggabungkan solusi array asosiatif satu jawaban untuk menghilangkan .indexOf()panggilan dalam loop yang banyak memperlambatnya dengan loop kedua, dan menyertakan beberapa optimasi lain yang disarankan pengguna lain dalam jawaban mereka juga. .

Jawaban teratas di sini dengan loop ganda pada setiap nilai (i-1) masih jauh lebih lambat. lodash masih melakukan yang kuat, dan saya masih akan merekomendasikan hal ini kepada siapa pun yang tidak keberatan menambahkan perpustakaan ke proyek mereka. Bagi mereka yang tidak mau, loop sementara saya masih merupakan jawaban yang baik dan jawaban filter memiliki tampilan yang sangat kuat di sini, mengalahkan semua tes saya dengan Canary Chrome terbaru (44.0.2360) pada tulisan ini.

Periksa jawaban Mike dan jawaban Dan Stocker jika Anda ingin meningkatkannya dengan cepat. Itu adalah yang tercepat dari semua hasil setelah melewati hampir semua jawaban yang layak.


Ada kekurangan dalam metodologi Anda: Anda menempatkan pembuatan array3 ke dalam tahap pengaturan, sementara biaya itu hanya akan menjadi bagian dari skor solusi berbasis sementara Anda. Dengan 1 baris ini bergerak , solusi Anda jatuh ke kecepatan loop berbasis. Saya mengerti bahwa array dapat digunakan kembali, tetapi mungkin algoritma lain juga dapat mengambil manfaat dari tidak harus mendeklarasikan dan menginisialisasi setiap blok bangunan yang diperlukan.
doldt

Saya setuju dengan premis Anda @doldt, tetapi tidak setuju dengan hasil Anda. Ada cacat desain mendasar dengan penghapusan entri berbasis loop, di mana Anda harus memeriksa ulang panjang array setelah Anda menghapus item, sehingga waktu eksekusi lebih lambat. Loop sementara bekerja mundur tidak memiliki efek ini. Berikut adalah contoh dengan menghapus variabel pengaturan sebanyak mungkin tanpa mengubah terlalu banyak jawaban aslinya: jsperf.com/merge-two-arrays-keeping-only-unique-values/19
slickplaid

@slickplaid tes tertaut kosong, dan revisi berikutnya di jsperf hang di loop while.
doldt

@doldt Saya telah menjawab kekhawatiran Anda dalam jawaban saya dan menambahkan tes yang diperbarui dengan benar juga. Beritahu saya jika Anda setuju dengan hasil itu atau tidak. Juga, saya menambahkan hasil lain yang lebih baik menggunakan array asosiatif.
Slickplaid

1
@slickplaid Terima kasih telah menyiapkan halaman perf yang diperluas. Kecuali saya melewatkan sesuatu, fungsi "whileLoopAlt2" tidak berfungsi? Ini menciptakan array baru yang berisi array pertama, dan array kedua (dalam urutan terbalik). Untuk menghindari kebingungan, saya telah membuat revisi lain yang menghilangkan fungsi yang rusak. Saya juga menambahkan contoh tambahan: jsperf.com/merge-two-arrays-keeping-only-unique-values/22
Stephen S

37

Anda dapat melakukannya hanya dengan ECMAScript 6,

var array1 = ["Vijendra", "Singh"];
var array2 = ["Singh", "Shakya"];
var array3 = [...new Set([...array1 ,...array2])];
console.log(array3); // ["Vijendra", "Singh", "Shakya"];
  • Gunakan operator spread untuk menggabungkan array.
  • Gunakan Set untuk membuat set elemen yang berbeda.
  • Sekali lagi gunakan operator spread untuk mengubah Set menjadi array.

2
Saya mendapatkan kesalahan: Ketik 'Set <string>' bukan tipe array.
gattsbr

3
Dan jika Anda untuk beberapa alasan tidak ingin menggunakan penyebaran operator, ada juga: Array.from(new Set(array1.concat(array2))).
kba

@gattsbr, dengan naskah di tsconfig.json, Anda dapat menambahkan "downlevelIteration": trueuntuk compilerOptions.
VincentPerrin.com

19
Array.prototype.merge = function(/* variable number of arrays */){
    for(var i = 0; i < arguments.length; i++){
        var array = arguments[i];
        for(var j = 0; j < array.length; j++){
            if(this.indexOf(array[j]) === -1) {
                this.push(array[j]);
            }
        }
    }
    return this;
};

Fungsi gabungan array yang jauh lebih baik.


4
var test = ['a', 'b', 'c']; console.log(test); akan mencetak ["a", "b", "c", merge: function]
Doubidou

Solusi yang sangat baik. Saya telah memperbarui tes jsperf yang diposting di atas oleh @slickplaid ( jsperf.com/merge-two-arrays-keeping-only-unique-values/3 ) dan sepertinya ini adalah yang tercepat di antara mereka.
Cobra

@Cobra Dengan risiko terdengar kecil, berjalan di Chrome 40.0.2214 (Terbaru pada 2/18/15), jawaban ini lebih lambat 53% dari saya. OTOH IE11 sepertinya tidak dioptimalkan untuk jawaban saya sama sekali. :) Chrome mobile masih mengguncangnya. Jujur, jika Anda menggunakan lodash / _ yang kebanyakan dari kita seharusnya, jawaban yang sebenarnya sudah cukup tinggi di daftar ini. :)
slickplaid

@ Slickplaid Benar, dan ini sedikit lebih cepat, bahkan dibandingkan dengan lodash / _ satu. Saya mungkin akan berakhir beralih implementasi saya pada satu titik atau yang lain untuk sesuatu yang mirip dengan Anda : D
Cobra

1
Tidak yakin berapa biaya metode indexOf () tetapi ini mungkin metode yang kompatibel dengan ES5 tercepat. Juga tidak ada artinya sama sekali bahwa panjang variabel argumen tidak diperlukan. Metode ini tidak dapat dilacak. @slickplaid Memuat perpustakaan tidak pernah merupakan jawaban untuk pertanyaan "bagaimana melakukannya dalam javascript". pasti banyak perpustakaan memiliki fungsi untuk menyelesaikan pekerjaan 7 baris ini.
dehart

19

Hanya melempar dua sen saya.

function mergeStringArrays(a, b){
    var hash = {};
    var ret = [];

    for(var i=0; i < a.length; i++){
        var e = a[i];
        if (!hash[e]){
            hash[e] = true;
            ret.push(e);
        }
    }

    for(var i=0; i < b.length; i++){
        var e = b[i];
        if (!hash[e]){
            hash[e] = true;
            ret.push(e);
        }
    }

    return ret;
}

Ini adalah metode yang saya gunakan banyak, menggunakan objek sebagai tabel hashlookup untuk melakukan pemeriksaan duplikat. Dengan asumsi bahwa hash adalah O (1), maka ini berjalan di O (n) di mana n adalah a.length + b.length. Jujur saya tidak tahu bagaimana browser melakukan hash, tetapi berkinerja baik pada ribuan titik data.


Dilakukan dengan sangat baik. Mengalahkan cukup (jika tidak semua) hasil lainnya pada halaman ini dengan memanfaatkan array asosiatif dan mencegah pengulangan indexOf dan operasi lainnya. jsperf.com/merge-two-arrays-keeping-only-unique-values/21
slickplaid

"Hash" Anda adalah String()fungsi dalam javascript. Yang mungkin bekerja untuk nilai-nilai primitif (meskipun dengan tabrakan antar tipe), tetapi itu tidak cocok untuk array objek.
Bergi

Saya menggunakan solusi serupa, saya mengizinkan lewat fungsi kode hash atau melewatkan string untuk mengidentifikasi properti di objek untuk digunakan sebagai kunci hash.
Robert Baker

19

Hanya menghindari loop bersarang (O (n ^ 2)), dan .indexOf()(+ O (n)).

function merge(a, b) {
    var hash = {}, i;
    for (i=0; i<a.length; i++) {
        hash[a[i]]=true;
    } 
    for (i=0; i<b.length; i++) {
        hash[b[i]]=true;
    } 
    return Object.keys(hash);
}

2
Itu cukup luar biasa, terutama jika Anda melakukan string. Angka akan membutuhkan langkah tambahan untuk mempertahankannya. Fungsi ini dengan berat mengalahkan semua opsi lain jika Anda tidak keberatan (atau peduli) bahwa semuanya adalah string setelah Anda selesai. Pekerjaan yang baik. Hasil kinerja di sini: jsperf.com/merge-two-arrays-keeping-only-unique-values/21
slickplaid

18

Jawaban terbaik yang disederhanakan dan mengubahnya menjadi fungsi yang menyenangkan:

function mergeUnique(arr1, arr2){
    return arr1.concat(arr2.filter(function (item) {
        return arr1.indexOf(item) === -1;
    }));
}

2
Saya percaya ini jauh lebih bersih daripada jawaban yang diterima. Juga sepertinya filter didukung dalam ECMAScript 5.1 + yang cukup didukung sekarang.
Tom Fobear

Ini seharusnya diterima
pukulan

ini jauh lebih ringkas.
Mox

15

Mengapa Anda tidak menggunakan objek? Sepertinya Anda mencoba memodelkan set. Namun, ini tidak akan mempertahankan pesanan.

var set1 = {"Vijendra":true, "Singh":true}
var set2 = {"Singh":true,  "Shakya":true}

// Merge second object into first
function merge(set1, set2){
  for (var key in set2){
    if (set2.hasOwnProperty(key))
      set1[key] = set2[key]
  }
  return set1
}

merge(set1, set2)

// Create set from array
function setify(array){
  var result = {}
  for (var item in array){
    if (array.hasOwnProperty(item))
      result[array[item]] = true
  }
  return result
}

Bukankah maksud Anda if (!set1.hasOwnProperty(key))?
Gumbo

2
Mengapa saya bersungguh-sungguh? Tujuan dari kondisi itu adalah untuk mengabaikan properti yang mungkin ada dalam prototipe objek.
Nick Retallack

12

Solusi terbaik...

Anda dapat memeriksa langsung di konsol peramban dengan menekan ...

Tanpa duplikat

a = [1, 2, 3];
b = [3, 2, 1, "prince"];

a.concat(b.filter(function(el) {
    return a.indexOf(el) === -1;
}));

Dengan duplikat

["prince", "asish", 5].concat(["ravi", 4])

Jika Anda ingin tanpa duplikat, Anda dapat mencoba solusi yang lebih baik dari sini - Kode Shouting .

[1, 2, 3].concat([3, 2, 1, "prince"].filter(function(el) {
    return [1, 2, 3].indexOf(el) === -1;
}));

Coba di konsol browser Chrome

 f12 > console

Keluaran:

["prince", "asish", 5, "ravi", 4]

[1, 2, 3, "prince"]

Itu tidak menghapus duplikat dari array keluaran.
Shahar

9

Satu setengah dolar saya:

Array.prototype.concat_n_dedupe = function(other_array) {
  return this
    .concat(other_array) // add second
    .reduce(function(uniques, item) { // dedupe all
      if (uniques.indexOf(item) == -1) {
        uniques.push(item);
      }
      return uniques;
    }, []);
};

var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];

var result = array1.concat_n_dedupe(array2);

console.log(result);

Itu tidak menggunakan apa pun yang baru di ES6, apakah saya melewatkan sesuatu?
Bergi

@Bergi: Ya, Anda benar. Terima kasih atas perhatiannya. Entah bagaimana saya bermain dengan skrip ini dan mungkin ada beberapa versi dengan fungsi ES6, tapi sekarang ini berisi indexOf yang sudah ada selama berabad-abad. Kesalahan saya, maaf.
Pahlawan Qu

8

Anda dapat mencapainya hanya menggunakan Underscore.js's => uniq :

array3 = _.uniq(array1.concat(array2))

console.log(array3)

Ini akan mencetak ["Vijendra", "Singh", "Shakya"] .


7

Untuk ES6, hanya satu baris:

a = [1, 2, 3, 4]
b = [4, 5]
[...new Set(a.concat(b))]  // [1, 2, 3, 4, 5]

7

Saya tahu pertanyaan ini bukan tentang berbagai objek, tetapi pencari berakhir di sini.

jadi ada baiknya menambahkan bagi pembaca di masa depan cara penggabungan ES6 yang tepat dan kemudian menghapus duplikat

berbagai objek :

var arr1 = [ {a: 1}, {a: 2}, {a: 3} ];
var arr2 = [ {a: 1}, {a: 2}, {a: 4} ];

var arr3 = arr1.concat(arr2.filter( ({a}) => !arr1.find(f => f.a == a) ));

// [ {a: 1}, {a: 2}, {a: 3}, {a: 4} ]

6
//Array.indexOf was introduced in javascript 1.6 (ECMA-262) 
//We need to implement it explicitly for other browsers, 
if (!Array.prototype.indexOf)
{
  Array.prototype.indexOf = function(elt, from)
  {
    var len = this.length >>> 0;

    for (; from < len; from++)
    {
      if (from in this &&
          this[from] === elt)
        return from;
    }
    return -1;
  };
}
//now, on to the problem

var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];

var merged = array1.concat(array2);
var t;
for(i = 0; i < merged.length; i++)
  if((t = merged.indexOf(i + 1, merged[i])) != -1)
  {
    merged.splice(t, 1);
    i--;//in case of multiple occurrences
  }

Implementasi indexOfmetode untuk browser lain diambil dari MDC


1
Saya tidak dapat menemukannya di w3schools, itu sebabnya saya menulisnya. w3schools.com/jsref/jsref_obj_array.asp Apakah dibutuhkan fromparameter btw?
Amarghosh

Terima kasih @Gumbo dan @meder - akan mengubah bookmark saya sekarang. Saya belum melakukan sesuatu yang serius di js dan saya menggunakan w3schools untuk referensi biasa (itu saja yang saya butuhkan) - mungkin itu sebabnya saya tidak menyadarinya.
Amarghosh

MDC mengatakan indexOf memerlukan javascript 1.6 Apakah aman untuk berasumsi bahwa browser umum (> = FF2,> IE6 dll) akan mendukungnya?
Amarghosh

4
IE6 tidak mendukung Array.prototype.indexOf, cukup tempelkan metode dukungan yang diberikan oleh Mozilla sehingga IE tidak melempar kesalahan.
meder omuraliev

diperbarui menggunakan indexOf. Membersihkan kode dengan menghapus bagian komentar. @meder - terima kasih lagi.
Amarghosh

6

Solusi baru (yang menggunakan Array.prototype.indexOfdan Array.prototype.concat):

Array.prototype.uniqueMerge = function( a ) {
    for ( var nonDuplicates = [], i = 0, l = a.length; i<l; ++i ) {
        if ( this.indexOf( a[i] ) === -1 ) {
            nonDuplicates.push( a[i] );
        }
    }
    return this.concat( nonDuplicates )
};

Pemakaian:

>>> ['Vijendra', 'Singh'].uniqueMerge(['Singh', 'Shakya'])
["Vijendra", "Singh", "Shakya"]

Array.prototype.indexOf (untuk penjelajah internet):

Array.prototype.indexOf = Array.prototype.indexOf || function(elt)
  {
    var len = this.length >>> 0;

    var from = Number(arguments[1]) || 0;
    from = (from < 0) ? Math.ceil(from): Math.floor(from); 
    if (from < 0)from += len;

    for (; from < len; from++)
    {
      if (from in this && this[from] === elt)return from;
    }
    return -1;
  };

@Mender: jika pesanan tidak masalah maka bagaimana saya melakukan ini
Vijjendra

1
Ini bukan metode ECMAScript standar yang ditentukan untuk Array.prototype, meskipun saya sadar Anda dapat dengan mudah mendefinisikannya untuk IE dan browser lain yang tidak mendukungnya.
meder omuraliev

Perhatikan bahwa algoritma ini adalah O (n ^ 2).
Gumbo

Algoritme apa jawaban Anda?
meder omuraliev

@meder: Algoritme saya adalah algoritma gabungan. Penyatuan itu sendiri dilakukan dalam O (n + m), tetapi penyortiran mengambil paling banyak O (n · log n + m · log m). Jadi keseluruhan algoritma adalah O (n · log n + m · log m).
Gumbo

6

Itu bisa dilakukan menggunakan Set.

var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];

var array3 = array1.concat(array2);
var tempSet = new Set(array3);
array3 = Array.from(tempSet);

//show output
document.body.querySelector("div").innerHTML = JSON.stringify(array3);
<div style="width:100%;height:4rem;line-height:4rem;background-color:steelblue;color:#DDD;text-align:center;font-family:Calibri" > 
  temp text 
</div>


6

Ada begitu banyak solusi untuk menggabungkan dua array. Mereka dapat dibagi menjadi dua kategori utama (kecuali penggunaan perpustakaan pihak ke-3 seperti lodash atau underscore.js).

a) menggabungkan dua array dan menghapus item yang digandakan.

b) memfilter item sebelum menggabungkannya.

Gabungkan dua array dan hapus item yang digandakan

Menggabungkan

// mutable operation(array1 is the combined array)
array1.push(...array2);
array1.unshift(...array2);

// immutable operation
const combined = array1.concat(array2);
const combined = [...array1, ...array2];    // ES6

Menyatukan

Ada banyak cara untuk menyatukan array, saya pribadi menyarankan di bawah dua metode.

// a little bit tricky
const merged = combined.filter((item, index) => combined.indexOf(item) === index);
const merged = [...new Set(combined)];

Saring item sebelum menggabungkannya

Ada juga banyak cara, tetapi saya pribadi menyarankan kode di bawah ini karena kesederhanaannya.

const merged = array1.concat(array2.filter(secItem => !array1.includes(secItem)));

5
Array.prototype.add = function(b){
    var a = this.concat();                // clone current object
    if(!b.push || !b.length) return a;    // if b is not an array, or empty, then return a unchanged
    if(!a.length) return b.concat();      // if original is empty, return b

    // go through all the elements of b
    for(var i = 0; i < b.length; i++){
        // if b's value is not in a, then add it
        if(a.indexOf(b[i]) == -1) a.push(b[i]);
    }
    return a;
}

// Example:
console.log([1,2,3].add([3, 4, 5])); // will output [1, 2, 3, 4, 5]

5
array1.concat(array2).filter((value, pos, arr)=>arr.indexOf(value)===pos)

Yang menyenangkan tentang yang satu ini adalah kinerja dan bahwa Anda secara umum, ketika bekerja dengan array, adalah metode chaining seperti filter, peta, dll sehingga Anda dapat menambahkan baris itu dan itu akan menggabungkan dan menduplikat array2 dengan array1 tanpa perlu referensi ke nanti satu (ketika Anda menggunakan metode chaining yang tidak Anda miliki), contoh:

someSource()
.reduce(...)
.filter(...)
.map(...) 
// and now you want to concat array2 and deduplicate:
.concat(array2).filter((value, pos, arr)=>arr.indexOf(value)===pos)
// and keep chaining stuff
.map(...)
.find(...)
// etc

(Saya tidak suka mencemari Array.prototype dan itu akan menjadi satu-satunya cara untuk menghormati rantai - mendefinisikan fungsi baru akan merusaknya - jadi saya pikir sesuatu seperti ini adalah satu-satunya cara untuk mencapainya)


4

Anda dapat mencoba ini:

const union = (a, b) => Array.from(new Set([...a, ...b]));

console.log(union(["neymar","messi"], ["ronaldo","neymar"]));


3

Pendekatan fungsional dengan ES2015

Mengikuti pendekatan fungsional a uniondari dua Arrays hanya komposisi concatdan filter. Untuk memberikan kinerja yang optimal, kami menggunakan Settipe data asli , yang dioptimalkan untuk pencarian properti.

Lagi pula, pertanyaan utama dalam hubungannya dengan unionfungsi adalah bagaimana memperlakukan duplikat. Permutasi berikut dimungkinkan:

Array A      + Array B

[unique]     + [unique]
[duplicated] + [unique]
[unique]     + [duplicated]
[duplicated] + [duplicated]

Dua permutasi pertama mudah ditangani dengan satu fungsi. Namun, dua yang terakhir lebih rumit, karena Anda tidak dapat memprosesnya selama Anda mengandalkan Setpencarian. Karena beralih ke Objectpencarian properti lama biasa akan memerlukan kinerja yang serius, implementasi berikut ini hanya mengabaikan permutasi ketiga dan keempat. Anda harus membuat versi terpisah unionuntuk mendukung mereka.


// small, reusable auxiliary functions

const comp = f => g => x => f(g(x));
const apply = f => a => f(a);
const flip = f => b => a => f(a) (b);
const concat = xs => y => xs.concat(y);
const afrom = apply(Array.from);
const createSet = xs => new Set(xs);
const filter = f => xs => xs.filter(apply(f));


// de-duplication

const dedupe = comp(afrom) (createSet);


// the actual union function

const union = xs => ys => {
  const zs = createSet(xs);  
  return concat(xs) (
    filter(x => zs.has(x)
     ? false
     : zs.add(x)
  ) (ys));
}


// mock data

const xs = [1,2,2,3,4,5];
const ys = [0,1,2,3,3,4,5,6,6];


// here we go

console.log( "unique/unique", union(dedupe(xs)) (ys) );
console.log( "duplicated/unique", union(xs) (ys) );

Dari sini, sepele untuk mengimplementasikan suatu unionnfungsi, yang menerima sejumlah array (terinspirasi oleh komentar naomik):

// small, reusable auxiliary functions

const uncurry = f => (a, b) => f(a) (b);
const foldl = f => acc => xs => xs.reduce(uncurry(f), acc);

const apply = f => a => f(a);
const flip = f => b => a => f(a) (b);
const concat = xs => y => xs.concat(y);
const createSet = xs => new Set(xs);
const filter = f => xs => xs.filter(apply(f));


// union and unionn

const union = xs => ys => {
  const zs = createSet(xs);  
  return concat(xs) (
    filter(x => zs.has(x)
     ? false
     : zs.add(x)
  ) (ys));
}

const unionn = (head, ...tail) => foldl(union) (head) (tail);


// mock data

const xs = [1,2,2,3,4,5];
const ys = [0,1,2,3,3,4,5,6,6];
const zs = [0,1,2,3,4,5,6,7,8,9];


// here we go

console.log( unionn(xs, ys, zs) );

Ternyata unionnhanya foldl(alias Array.prototype.reduce), yang uniondianggap sebagai peredamnya. Catatan: Karena implementasi tidak menggunakan akumulator tambahan, itu akan menimbulkan kesalahan ketika Anda menerapkannya tanpa argumen.


1
beberapa umpan balik: Saya perhatikan itu flipdan notftidak digunakan. unionByRincian implementasi kebocoran juga predikat (memerlukan pengetahuan Settipe implisit ). Mungkin menyenangkan jika Anda bisa melakukan sesuatu seperti ini: union = unionBy (apply)dan unionci = unionBy (p => x => p(x.toLowerCase())). Dengan cara itu pengguna hanya mengirim apa pun nilai pengelompokannya p- hanya sebuah ide ^ _ ^
Terima kasih

zsdeklarasi variabel juga kurang var/ letkata kunci
Terima kasih

1
inilah cuplikan kode yang akan diklarifikasi [inti: unionBy.js ]
Terima kasih

@naomik Setelah memikirkan kembali solusi saya untuk sementara waktu saya tidak begitu yakin lagi apakah itu cara yang tepat untuk melewati predikat. Yang Anda dapatkan adalah transformasi dari setiap elemen dari array kedua. Saya ingin tahu apakah pendekatan ini memecahkan lebih dari sekedar masalah mainan.

3

untuk itu ... berikut ini adalah solusi jalur tunggal:

const x = [...new Set([['C', 'B'],['B', 'A']].reduce( (a, e) => a.concat(e), []))].sort()
// ['A', 'B', 'C']

Tidak terlalu mudah dibaca tetapi dapat membantu seseorang:

  1. Menerapkan fungsi perkecil dengan nilai akumulator awal diatur ke array kosong.
  2. Fungsi pengurangan menggunakan concat untuk menambahkan setiap sub-array ke array akumulator.
  3. Hasil ini dilewatkan sebagai parameter konstruktor untuk membuat yang baru Set.
  4. Operator spread digunakan untuk mengubah Setarray.
  5. The sort()Fungsi diterapkan ke array baru.

2
Selain itu, reduce()Anda tidak dapat menggunakanArray.from(set)
Eran Goldin

3

DeDuplicate single atau Gabungkan dan DeDuplicate input larik ganda. Contoh di bawah ini.

menggunakan ES6 - Set, untuk, perusakan

Saya menulis fungsi sederhana ini yang mengambil beberapa argumen array. Apakah hampir sama dengan solusi di atas itu hanya memiliki kasus penggunaan yang lebih praktis. Fungsi ini tidak menggabungkan nilai duplikat ke satu array saja sehingga dapat menghapusnya di beberapa tahap kemudian.

DEFINISI FUNGSI SINGKAT (hanya 9 baris)

/**
* This function merging only arrays unique values. It does not merges arrays in to array with duplicate values at any stage.
*
* @params ...args Function accept multiple array input (merges them to single array with no duplicates)
* it also can be used to filter duplicates in single array
*/
function arrayDeDuplicate(...args){
   let set = new Set(); // init Set object (available as of ES6)
   for(let arr of args){ // for of loops through values
      arr.map((value) => { // map adds each value to Set object
         set.add(value); // set.add method adds only unique values
      });
   }
   return [...set]; // destructuring set object back to array object
   // alternativly we culd use:  return Array.from(set);
}

GUNAKAN CONTOH CODEPEN :

// SCENARIO 
let a = [1,2,3,4,5,6];
let b = [4,5,6,7,8,9,10,10,10];
let c = [43,23,1,2,3];
let d = ['a','b','c','d'];
let e = ['b','c','d','e'];

// USEAGE
let uniqueArrayAll = arrayDeDuplicate(a, b, c, d, e);
let uniqueArraySingle = arrayDeDuplicate(b);

// OUTPUT
console.log(uniqueArrayAll); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 43, 23, "a", "b", "c", "d", "e"]
console.log(uniqueArraySingle); // [4, 5, 6, 7, 8, 9, 10]

Kenapa menggunakan arr.mapdisini? Anda menggunakannya sebagai foreach, karena hasilnya diabaikan
Antony

Saya menggunakan return Array.from (set.values ​​()); , karena vscode memberikan kesalahan untuk pengembalian [... set];
makkasi

3
var arr1 = [1, 3, 5, 6];
var arr2 = [3, 6, 10, 11, 12];
arr1.concat(arr2.filter(ele => !arr1.includes(ele)));
console.log(arr1);

output :- [1, 3, 5, 6, 10, 11, 12]

3

var array1 = ["one","two"];
var array2 = ["two", "three"];
var collectionOfTwoArrays = [...array1, ...array2];    
var uniqueList = array => [...new Set(array)];
console.log('Collection :');
console.log(collectionOfTwoArrays);    
console.log('Collection without duplicates :');
console.log(uniqueList(collectionOfTwoArrays));

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.