JavaScript'te iki diziyi birleştirme ve yinelenen öğeleri kaldırma


1365

İki JavaScript dizim var:

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

Çıktı olmasını istiyorum:

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

Çıktı dizisinde yinelenen sözcükler kaldırılmış olmalıdır.

Her diziden yalnızca benzersiz öğeleri orijinal dizilere eklendikleri sırayla elde edebilmem için iki diziyi JavaScript'te nasıl birleştiririm?


1
Yeni bir yanıt göndermeden önce, bu soru için 75'ten fazla yanıt olduğunu düşünün. Lütfen yanıtınızın mevcut yanıtlar arasında yer almayan bilgilere katkıda bulunduğundan emin olun.
janniks

[... yeni Set ([... [1, 2, 3], ... [2, 3, 4]]))] sonuç [1, 2, 3, 4]
Denis Giffeler

Derin birleşmeyi de kapsayan daha genel bir çözüm istiyorsanız , bunun yerine bu soruya bir göz atın . Bazı cevaplar da dizileri kapsamaktadır.
Martin Braun

Yanıtlar:


1664

Dizileri birleştirmek için (yinelenenleri kaldırmadan)

ES5 sürümü kullanımı Array.concat:

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

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

ES6 sürümü kullanım yıkımı

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

Kopyaları kaldırmak için 'yerleşik' bir yol olmadığından ( ECMA-262 aslında Array.forEachbunun için harika olurdu), bunu manuel olarak yapmalıyız:

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

Ardından, kullanmak için:

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

Bu, dizilerin sırasını da koruyacaktır (yani, sıralama gerekli değildir).

Birçok insan prototip büyütme Array.prototypeve for indöngülerden rahatsız olduğu için, bunu kullanmanın daha az invaziv bir yolu var:

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

ES5'in kullanılabildiği tarayıcılarla çalışacak kadar şanslı olanlar için şunları kullanabilirsiniz Object.defineProperty:

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
Bu algoritmanın O (n ^ 2) olduğuna dikkat edin.
Gumbo

7
Let [a, b, c]ve [x, b, d]diziler olmak (tırnak varsayalım). concat verir [a, b, c, x, b, d]. Unique () 'nin çıktısı olmaz [a, c, x, b, d]. Sanırım siparişi [a, b, c, x, d]
korumuyor

89
OP onu çalıştıran ilk cevabı kabul etti ve anlaşıldı. Hala birbirimizin çözümlerini karşılaştırıyoruz, hataları tespit ediyoruz, performansı geliştiriyoruz, her yerde uyumlu olduğundan emin
oluyoruz

6
Başlangıçta buna oy verdim ama fikrimi değiştirdim. Array.prototype'e prototip atamanın, "için ..." ifadelerini kırmanın sonuçları vardır. Bu yüzden en iyi çözüm muhtemelen böyle bir işlevi kullanmaktır ancak prototip olarak atamamaktır. Bazı insanlar, "for ... in" ifadelerinin yine de dizi öğelerini yinelemek için kullanılmaması gerektiğini savunabilir, ancak insanlar bunları genellikle bu şekilde kullanırlar, bu nedenle en azından bu çözüm dikkatle kullanılmalıdır.
Kod Komutanı

16
her zaman kullanmalısınız for ... inile hasOwnPropertybu durumda prototip yöntemi gayet
mulllhausen

600

Underscore.js veya Lo-Dash ile şunları yapabilirsiniz:

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
Veya, alt çizgiden bile daha iyi, API uyumlu lodash .
Brian M. Hunt

3
@Ygg Lodash belgelerinden. Msgstr "Dizilerden bir veya daha fazlasında bulunan yeni benzersiz değerler dizisini sırayla döndürür ."
Richard Ayotte

4
Underscore.js'yi tercih ederim. Ne kullanarak sona erdi underscore.flatten(), bir dizi diziler alır çünkü sendika daha iyidir.
dokumacı

8
@weaver _.flatten birleşir, ancak 'çoğaltılmaz'.
GijsjanB

9
Lodash'a karşı en iyi cevaba hızlı performans: jsperf.com/merge-two-arrays-keeping-only-unique-values
slickplaid

288

Önce iki diziyi birleştirin, ardından yalnızca benzersiz öğeleri filtreleyin:

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]

Düzenle

Önerildiği gibi, daha performanslı bir akıllıca çözüm, benzersiz öğeleri aşağıdakilerle bbirleştirmeden önce filtrelemek olacaktır 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
Buradaki orijinal çözüm, her kaynak dizisi içindeki çiftleri kaldırma avantajına sahiptir. Sanırım hangi bağlamda kullanacağınıza bağlı.
theGecko

IE6 desteği için farklı birleştirme yapabilirsiniz: c = Array.from (yeni Set (c));
Tobi G.

aEklemek için gerçekten değiştirmek istersem b, döngü yapmak ve push kullanmak daha iyi olur mu? a.forEach(function(item){ if(a.indexOf(item)<0) a.push(item); });
huşu

1
IE6 konusunda endişeli kişiler için caniuse.com/usage-table tarayıcı kullanımının hatırlatıcısı .
pmrotule

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

203

Bu, forma operatörü ve dizi jeneriklerini kullanan bir ECMAScript 6 çözümüdür .

Şu anda yalnızca Firefox ve muhtemelen Internet Explorer Teknik Önizleme ile çalışıyor.

Ama Babil'i kullanırsan , şimdi alabilirsin.

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
Bu, kabul edilen cevaba eklenmelidir. Bu çözüm, şu anda mümkün olandan çok daha verimli ve çok daha zariftir, ancak kaçınılmaz olarak yapabileceğimiz (ve bu alanda yetişmek için yapmamız gereken) budur.
EmmaGamma

Bu OP'nin sorusuyla aynı değil (bu her şeyden çok bir flatmap gibi görünüyor) ama oy kullan çünkü harika.
jedd.ahyoung

4
Sorunun 2009'dan beri kabul edilen cevap olması gerektiğini söylemek zor. Ama evet, bu sadece daha "performans" değil, aynı zamanda "zarif"
Cezar Augusto

11
Array.fromforma operatörü yerine kullanılabilir: Array.from(new Set([].concat(...arr)))
Henry Blyth

1
Bu çok zarif. Maalesef Typescript henüz bunu desteklemiyor. stackoverflow.com/questions/33464504/…
Ben Carp

190

ES6

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

VEYA

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

VEYA

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

1
1. / 2. örnek hiç değil union+ 1. örnek büyük Arrays için yığını havaya uçuruyor + 3. örnek inanılmaz derecede yavaş ve çok fazla bellek tüketiyor, çünkü iki ara Arrays inşa edilmesi gerekiyor + 3. örnek sadece unionbilinen bir ile kullanılabilir Arrayderleme zamanında s sayısı .

nasıl yapardın?
David Noreña

14
Setburaya gitmenin yolu
philk

3
Set için, aynı anahtar değeri çiftine sahip iki nesneyi aynı nesne başvuruları olmadıkça tekilleştiremezsiniz.
Jun711

2
Yalnızca nesne referanslarını birleştireceğinden ve nesnelerin kendilerinin eşit olup olmadığını umursamadığından, bir nesne dizisiyle çalışmaz.
Wilson Biggs

87

Bir Set (ECMAScript 2015) kullanarak , bu kadar basit olacaktır:

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


7
Bunu ES6 kullanmak için "Kabul Edilen Cevap" olarak değerlendiriyorum.
mwieczorek

9
@mwieczorek Nasıl yapılır:const array3 = [...new Set(array1.concat(array2))]
Robby Cornelissen

5
Bir nesne dizisi kullanıyorsanız işe yaramaz
carkod

1
farklı nesneleri çoğaltmadan birleştirmek için: stackoverflow.com/a/54134237/3131433
Rakibul Haq

38

İşte döngüden biraz farklı bir bakış. Chrome'un en son sürümündeki bazı optimizasyonlarla, iki dizinin birleşimini çözmek için en hızlı yöntemdir (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);
  }
}

while döngüsü: ~ 589k ops / s
filtresi: ~ 445k ops / s
lodash: 308k ops / s
döngüler için 308k ops / s: 225k ops / s

Bir yorum, kurulum değişkenlerimden birinin döngümün geri kalanının önüne geçmesine neden olduğunu belirtti, çünkü yazmak için boş bir dizi başlatmak zorunda değildi. Buna katılıyorum, bu yüzden testi oyun alanına bile yeniden yazdım ve daha hızlı bir seçenek ekledim.

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

Bu alternatif çözümde, bir yanıtın ilişkilendirilebilir dizi çözümünü .indexOf() döngüdeki çağrıyı ikinci bir döngü ile çok yavaşlatan çağrıyı ve diğer kullanıcıların da cevaplarında önerdiği diğer optimizasyonlardan bazılarını dahil ettim .

Burada her değerde (i-1) çift döngü bulunan en önemli cevap hala önemli ölçüde yavaştır. Lodash hala güçlü yapıyor ve hala projelerine bir kütüphane eklemeyi düşünmeyen herkese tavsiye ederim. İstemeyenler için while döngüm hala iyi bir yanıt ve filtre cevabının burada çok güçlü bir gösterimi var, bu yazımdan itibaren en son Canary Chrome (44.0.2360) ile yaptığım tüm testleri yeniyorum.

Check out Ahmet'in cevabı ve Dan Stocker yanıtını hızdaki bu bir çentik hızlandırmaya istiyorum. Bunlar, hemen hemen tüm uygulanabilir cevaplardan geçtikten sonra tüm sonuçların en hızlısıdır.


Metodolojinizde bir kusur var: dizi3'ün oluşturulmasını kurulum aşamasına koyarken, bu maliyet sadece süre tabanlı çözümünüzün puanının bir parçası olmalıdır. Bu 1 satır hareket ettirildiğinde , çözümünüz for döngüsü temelli olanın hızına düşer. Dizinin yeniden kullanılabileceğini anlıyorum, ancak belki de diğer algoritmalar, gerekli her yapı taşını bildirmek ve başlatmak zorunda kalmamaktan da yararlanabilir.
doldt

@Doldt öncülüne katılıyorum, ama sonuçlarına katılmıyorum. Girdilerin döngü tabanlı kaldırılmasıyla temel bir tasarım hatası vardır, çünkü öğeleri kaldırdıktan sonra dizinin uzunluğunu yeniden kontrol etmeniz ve daha yavaş bir yürütme süresi sağlamanız gerekir. Geriye doğru çalışan bir while döngüsünün bu etkileri yoktur. İşte orijinal yanıtlarını çok fazla değiştirmeden yapabildiğim kadar çok kurulum değişkenini kaldıran bir örnek: jsperf.com/merge-two-arrays-keeping-only-unique-values/19
slickplaid 15:15

@slickplaid bağlantılı testler boş ve jsperf'deki bir sonraki düzeltme while döngüsünde asılı kalıyor.
doldt

@doldt Cevabımdaki endişelerinizi giderdim ve buna güncelleştirilmiş bir test de ekledim. Bu sonuçları kabul edip etmediğinizi bize bildirin. Ayrıca, ilişkilendirilebilir bir dizi kullanarak başka bir daha iyi sonuç ekledim.
slickplaid

1
@slickplaid Genişletilmiş mükemmel sayfayı ayarladığınız için teşekkür ederiz. Bir şeyi kaçırmadıkça, "whileLoopAlt2" işlevi çalışmıyor mu? İlk diziyi ve ikinci diziyi (ters sırada) içeren yeni bir dizi oluşturur. Karışıklığı önlemek için bozuk işlevi kaldıran başka bir düzeltme daha yaptım. Ayrıca bir örnek daha ekledim: jsperf.com/merge-two-arrays-keeping-only-unique-values/22
Stephen S

37

Bunu sadece ECMAScript 6 ile yapabilirsiniz,

var array1 = ["Vijendra", "Singh"];
var array2 = ["Singh", "Shakya"];
var array3 = [...new Set([...array1 ,...array2])];
console.log(array3); // ["Vijendra", "Singh", "Shakya"];
  • Diziyi birleştirmek için forma işlecini kullanın .
  • Farklı bir öğe kümesi oluşturmak için Set'i kullanın .
  • Seti bir diziye dönüştürmek için forma operatörünü tekrar kullanın.

2
Hata alıyorum: 'Set <string>' bir dizi türü değil.
gattsbr

3
Eğer bazı nedenlerden dolayı yayılma operatörünü kullanmak istemiyorsanız Ve de var: Array.from(new Set(array1.concat(array2))).
kba

@gattsbr, içinde daktilo versiyonu ile tsconfig.json, ekleyebilirsiniz "downlevelIteration": truekadar 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;
};

Çok daha iyi dizi birleştirme işlevi.


4
var test = ['a', 'b', 'c']; console.log(test); yazdırılacak ["a", "b", "c", merge: function]
Doubidou

Mükemmel çözüm. Yukarıda slickplaid ( jsperf.com/merge-two-arrays-keeping-only-unique-values/3 ) tarafından yayınlanan jsperf testini güncelledim ve bu en hızlı olanı gibi görünüyor.
Cobra

@Cobra Chrome 40.0.2214'te (En son 2/18/15 itibariyle) önemsiz gibi görünme riski altında bu yanıt benimkinden% 53 daha yavaş. OTOH IE11, cevabım için hiç optimize edilmemiş gibi görünüyor. :) Chrome mobil yine de sallanıyor. Dürüst olmak gerekirse, çoğumuzun yapması gereken lodash / _ kullanıyorsanız, gerçek cevap zaten bu listede oldukça yüksektir. :)
slickplaid

@slickplaid True ve lodash / _ one ile karşılaştırıldığında bile biraz daha hızlı. Muhtemelen benim uygulamamı bir noktada ya da başka bir şeye benzer bir şeye çevireceğim. : D
Cobra

1
İndexOf () yönteminin maliyetlerinin ne olduğundan emin değilim, ancak bu muhtemelen en hızlı ES5 uyumlu yöntemdir. Ayrıca, değişkenlerin değişken uzunluğunun gerekli olmadığı hiçbir şeye değmez. Bu yöntem zincirlenebilir. @slickplaid Kitaplık yüklemek asla "javascript'te nasıl yapılır" sorusunun cevabı değildir. şüphesiz birçok kütüphane bu 7 satırlık işi yapmak için bir işleve sahiptir.
dehart

19

Sadece iki sentimi atıyorum.

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

Bu çok kullandığım bir yöntem, yinelenen kontrol yapmak için bir hashlookup tablosu olarak bir nesne kullanır. Karmanın O (1) olduğunu varsayarsak, bu n'nin bir uzunluk + b. uzunluk olduğu O (n) 'de çalışır. Dürüst olmak gerekirse tarayıcının karmayı nasıl yaptığı hakkında hiçbir fikrim yok, ancak binlerce veri noktasında iyi performans gösteriyor.


Çok iyi yapmışsın. İlişkili diziden yararlanarak ve indexOf ve diğer işlemlerin döngüsünü dışarıda bırakarak bu sayfadaki diğer sonuçların tümünü (tümü olmasa da) yener. jsperf.com/merge-two-arrays-keeping-only-unique-values/21
slickplaid

"Karma" String()javascript işlevidir. Bu, ilkel değerler (tipler arasındaki çarpışmalar da olsa) için işe yarayabilir, ancak nesnelerin dizileri için iyi bir uyum değildir.
Bergi

Benzer bir çözüm kullanıyorum, hashCode işlevini geçirmeye veya hash anahtarı olarak kullanılacak nesnedeki bir özelliği tanımlamak için bir dize geçirmeye izin veriyorum.
Robert Baker

19

İç içe döngülerden (O (n ^ 2)) ve .indexOf()(+ O (n)) uzak durmanız yeterlidir .

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
Bu oldukça şaşırtıcı, özellikle de ipliyorsanız. Sayıların bu şekilde kalması için ek bir adım gerekir. Bitirdikten sonra her şeyin bir dize olduğunu düşünmezseniz (veya umursamazsanız) bu işlev diğer tüm seçenekleri ağır bir şekilde yener. İyi iş. Performans sonuçları burada: jsperf.com/merge-two-arrays-keeping-only-unique-values/21
slickplaid

18

Bu cevabın en iyisi basitleştirildi ve hoş bir fonksiyona dönüştürüldü:

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

2
Bunun kabul edilen cevaptan çok daha temiz olduğuna inanıyorum. Ayrıca, şu anda oldukça desteklenen ECMAScript 5.1 + 'da filtre destekleniyor gibi görünüyor.
Tom Fobear

Bu kabul edilmiş olmalıydı
wallop

bu çok daha özlü.
Mox

15

Neden bir nesne kullanmıyorsunuz? Bir seti modellemeye çalıştığınız anlaşılıyor. Ancak bu siparişi korumaz.

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
}

Bunu mu demek istediniz if (!set1.hasOwnProperty(key))?
Gumbo

2
Neden bunu kastediyorum? Bu koşulun amacı, nesnenin prototipinde olabilecek özellikleri yok saymaktır.
Nick Retallack

12

En iyi çözüm...

Vurarak doğrudan tarayıcı konsolundan kontrol edebilirsiniz ...

Kopya olmadan

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

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

Yinelenen

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

Yinelenmeden isterseniz buradan daha iyi bir çözüm deneyebilirsiniz - Bağıran Kod .

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

Chrome tarayıcı konsolunda deneyin

 f12 > console

Çıktı:

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

[1, 2, 3, "prince"]

Çıktı dizisinden yinelenenleri kaldırmaz.
Shahar

9

Bir buçuk kuruşum:

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

ES6'da yeni bir şey kullanmıyor, bir şey mi kaçırdım?
Bergi

@Bergi: Evet, haklısın. Kaydettiğiniz için teşekkürler. Her nasılsa bu komut dosyasıyla oynuyordum ve muhtemelen ES6 işleviyle bazı sürümler vardı, ama şimdi yüzyıllardır orada bulunan indexOf'u içeriyor. Benim hatam, üzgünüm.
Hero Qu

8

Sadece Underscore.js'in => uniq'i kullanarak başarabilirsiniz :

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

console.log(array3)

Bu yazdırır [ "Vijendra", "Singh", "Shakya"] .


7

ES6 için sadece bir satır:

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

7

Bu sorunun nesneler dizisi ile ilgili olmadığını biliyorum, ancak arama yapanların burada bitmesi.

bu yüzden gelecekteki okuyucular için uygun bir ES6 birleştirme yöntemi eklemeye ve kopyaları kaldırmaya değer

nesne dizisi :

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
  }

indexOfDiğer tarayıcılar için yöntemin uygulanması MDC'den alınır


1
W3schools'ta bulamadım, bu yüzden yazdım. w3schools.com/jsref/jsref_obj_array.asp mu o almak frombtw parametre?
Amarghosh

@ @ Gumbo ve @meder - şimdi yer işaretlerimi değiştireceğim. Ben henüz js ciddi bir şey yapmak ve w3schools rahat başvuru için kullanın (şimdiye kadar ihtiyacım olan tek şey) - belki bu yüzden bunu fark etmedi.
Amarghosh

MDC, indexOf'un javascript 1.6 gerektirdiğini söylüyor. Ortak tarayıcıların (> = FF2,> IE6 vb.) Bunu destekleyeceğini varsaymak güvenli olur mu?
Amarghosh

4
IE6, Array.prototype.indexOf'u desteklemez, sadece Mozilla tarafından verilen destek yöntemini yapıştırın, böylece IE bir hata atmaz.
meder omuraliev

kullanılarak güncellendi indexOf. Yorumlanan kısmı kaldırarak kodu temizleyin. @meder - tekrar teşekkürler.
Amarghosh

6

Yeni çözüm (ki kullanımları Array.prototype.indexOfve 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 )
};

Kullanımı:

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

Array.prototype.indexOf (internet explorer için):

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: sipariş önemli değilse o zaman nasıl yaparım
Vijjendra

1
Array.prototype için tanımlanan standart bir ECMAScript yöntemi değildir, ancak IE ve onu desteklemeyen diğer tarayıcılar için kolayca tanımlayabileceğinizin farkındayım.
meder omuraliev

Bu algoritmanın O (n ^ 2) olduğuna dikkat edin.
Gumbo

Cevabınız hangi algoritma?
meder omuraliev

@meder: Algoritmam bir birleşim algoritmasıdır. Birliğin kendisi O (n + m) olarak yapılır, ancak sıralama en fazla O (n · log n + m · log m) alır. Yani tüm algoritma O (n · log n + m · log m) 'dir.
Gumbo

6

Set kullanılarak yapılabilir.

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

İki diziyi birleştirmek için çok fazla çözüm var. İki ana kategoriye ayrılabilirler (lodash veya underscore.js gibi 3. taraf kitaplıkların kullanımı hariç).

a) iki diziyi birleştirin ve çoğaltılan öğeleri kaldırın.

b) öğeleri birleştirmeden önce filtreleyin.

İki diziyi birleştirin ve çoğaltılan öğeleri kaldırın

birleştirme

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

Unifying

Bir diziyi birleştirmenin birçok yolu vardır, ben şahsen aşağıdaki iki yöntemi öneririm.

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

Öğeleri birleştirmeden önce filtreleyin

Ayrıca birçok yolu vardır, ancak ben şahsen basitliği nedeniyle aşağıdaki kodu öneririz.

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)

Bu konuda güzel bir şey performans ve genel olarak, dizilerle çalışırken, filtre, harita vb. biri (sahip olmadığınız yöntemleri zincirlerken), örnek:

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

(Array.prototype'i kirletmek istemiyorum ve zincire saygı duymanın tek yolu bu olurdu - yeni bir işlev tanımlamak onu kıracaktır - bu yüzden böyle bir şeyin bunu başarmanın tek yolu olduğunu düşünüyorum)


4

Bunu deneyebilirsiniz:

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

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


3

ES2015 ile fonksiyonel bir yaklaşım

Fonksiyonel bir yaklaşım aşağıdakı unioniki Arrays, sadece bileşimi concatve filter. Optimum performans sağlamak için yerelSet için özellik aramaları için optimize edilmiş veri türüne .

Her neyse, bir unionişlevle birlikte anahtar soru, kopyaların nasıl ele alınacağıdır. Aşağıdaki permütasyonlar mümkündür:

Array A      + Array B

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

İlk iki permütasyonun tek bir fonksiyonla kullanımı kolaydır. Bununla birlikte, son ikisi daha karmaşıktır, çünkü Setaramalara güvendiğiniz sürece bunları işleyemezsiniz . Sade eski Objectmülk aramalarına geçmek ciddi bir performans gerektireceğinden, aşağıdaki uygulama sadece üçüncü ve dördüncü permütasyonu göz ardı etmektedir. Bunları uniondesteklemek için ayrı bir sürümü oluşturmanız gerekir.


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

Buradan sonra unionn, herhangi bir sayıda diziyi kabul eden bir işlevi uygulamak önemsiz hale gelir (naomik'in yorumlarından esinlenerek):

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

Görünüşe göre unionnsadece foldl(aka Array.prototype.reduce), unionredüktörü olarak alır . Not: Uygulama ek bir akümülatör kullanmadığından, argüman olmadan uyguladığınızda hata verir.


1
birkaç geri bildirim: Bunu fark ettim flipve notfkullanılmıyor. Ayrıca unionBysızıntı uygulama ayrıntılarını da (örtük tür bilgisi gerektirir Set) belirleyin. Böyle bir şey yapabilmeniz hoş olabilir: union = unionBy (apply)ve unionci = unionBy (p => x => p(x.toLowerCase())). Bu şekilde kullanıcı sadece gruplama değeri ne olursa olsun gönderir p- sadece bir fikir ^ _ ^
Teşekkürler

zsdeğişken beyanı da yok var/ letanahtar kelime
Teşekkürler

1
İşte açıklığa kavuşturmak için bir kod pasajı [gist: unionBy.js ]
Teşekkürler

@naomik Bir süre çözümümü yeniden düşündükten sonra yüklemi geçmenin doğru yolu ise artık o kadar emin değilim. Elde ettiğiniz tek şey, ikinci dizinin her elemanının bir dönüşümüdür. Bu yaklaşımın oyuncak problemlerinden daha fazlasını çözüp çözmediğini merak ediyorum.

3

uğruna ... işte tek satırlık bir çözüm:

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

Özellikle okunabilir değil ancak birisine yardımcı olabilir:

  1. Başlangıç ​​akümülatör değeri boş bir diziye ayarlanmışken bir azaltma işlevi uygular.
  2. Azaltma işlevi, her alt diziyi toplayıcı dizisine eklemek için concat kullanır.
  3. Bunun sonucu, yeni bir oluşturmak için yapıcı parametresi olarak geçirilir Set .
  4. Forma işleci Setbir diziye dönüştürmek için kullanılır .
  5. sort()İşlev yeni diziye uygulanır.

2
Ayrıca yerine reduce()kullanabilirsinizArray.from(set)
Eran Goldin

3

Tekli deDuplicate veya Çoklu dizi girişlerini Birleştir ve DeDuplicate. Aşağıdaki örnek.

ES6 kullanmak - Yıkmak için

Birden fazla dizi argümanı alan bu basit işlevi yazdım. Yukarıdaki çözümle hemen hemen aynı mı, sadece daha pratik kullanım durumu var. Bu işlev yinelenen değerleri yalnızca bir dizide birleştirmez, böylece sonraki aşamalarda bunları silebilir.

KISA FONKSİYON TANIMI (sadece 9 satır)

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

ÖRNEK KODU :

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

Neden arr.mapburada kullanıyorsunuz? foreachSonuç olarak göz ardı edildiği için bunu bir olarak kullanıyorsunuz
Antony

Ben dönüş Array.from (set.values ​​()); , çünkü vscode dönüş [... 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));

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.