So führen Sie zwei Arrays in JavaScript zusammen und duplizieren Elemente

1366

Ich habe zwei JavaScript-Arrays:

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

Ich möchte, dass die Ausgabe lautet:

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

Das Ausgabearray sollte wiederholte Wörter entfernt haben.

Wie füge ich zwei Arrays in JavaScript zusammen, sodass ich nur die eindeutigen Elemente von jedem Array in derselben Reihenfolge erhalte, in der sie in die ursprünglichen Arrays eingefügt wurden?

Vijjendra
quelle
1
Bevor Sie eine neue Antwort veröffentlichen, sollten Sie berücksichtigen, dass diese Frage bereits über 75 Antworten enthält. Stellen Sie sicher, dass Ihre Antwort Informationen enthält, die nicht zu den vorhandenen Antworten gehören.
Janniks
[... neues Set ([... [1, 2, 3], ... [2, 3, 4]])] Ergebnis [1, 2, 3, 4]
Denis Giffeler
Wenn Sie eine allgemeinere Lösung wünschen, die auch das Deep-Merging abdeckt, werfen Sie stattdessen einen Blick auf diese Frage . Einige Antworten beziehen sich auch auf Arrays.
Martin Braun

Antworten:

1664

Einfach die Arrays zusammenführen (ohne Duplikate zu entfernen)

Verwendung der ES5-Version Array.concat:

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

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

Die ES6-Version verwendet Destrukturierung

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

Da es keine "eingebaute" Möglichkeit gibt, Duplikate zu entfernen ( ECMA-262 hat tatsächlich eine Array.forEachMöglichkeit, dies zu tun), müssen wir dies manuell tun:

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

Dann, um es zu benutzen:

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

Dadurch bleibt auch die Reihenfolge der Arrays erhalten (dh es ist keine Sortierung erforderlich).

Da sich viele Menschen über die Erweiterung Array.prototypeund for inSchleifen von Prototypen ärgern , gibt es hier eine weniger invasive Möglichkeit, sie zu verwenden:

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

Für diejenigen, die das Glück haben, mit Browsern zu arbeiten, in denen ES5 verfügbar ist, können Sie Folgendes verwenden 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;
    }
});
LiraNuna
quelle
281
Beachten Sie, dass dieser Algorithmus O (n ^ 2) ist.
Gumbo
7
Lassen Sie [a, b, c]und [x, b, d]seien Sie die Arrays (nehmen Sie Anführungszeichen an). concat gibt [a, b, c, x, b, d]. Wäre nicht die einzige () 's ausgegeben werden [a, c, x, b, d]. Das bewahrt nicht die Ordnung, die ich denke - ich glaube, OP will[a, b, c, x, d]
Amarghosh
89
OP akzeptierte die erste Antwort, die ihn zum Arbeiten brachte, und unterschrieb anscheinend. Wir vergleichen immer noch die Lösungen der anderen, finden Fehler und beheben sie, verbessern die Leistung, stellen sicher, dass sie überall kompatibel sind und so weiter ... Die Schönheit des Stackoverflow :-)
Amarghosh
6
Ich habe dies ursprünglich hochgestimmt, aber meine Meinung geändert. Das Zuweisen von Prototypen zu Array.prototype hat zur Folge, dass "for ... in" -Anweisungen gebrochen werden. Die beste Lösung besteht wahrscheinlich darin, eine solche Funktion zu verwenden, sie jedoch nicht als Prototyp zuzuweisen. Einige Leute mögen argumentieren, dass "for ... in" -Anweisungen sowieso nicht zum Iterieren von Array-Elementen verwendet werden sollten, aber die Leute verwenden sie oft so, so dass diese Lösung zumindest mit Vorsicht verwendet werden sollte.
Code Commander
16
verwenden Sie sollten immer for ... inmit hasOwnPropertyin diesem Fall der Prototyp - Methode ist in Ordnung
mulllhausen
600

Mit Underscore.js oder Lo-Dash können Sie Folgendes tun:

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

GijsjanB
quelle
70
Oder, vielleicht sogar besser als unterstreichen, das API-kompatible lodash .
Brian M. Hunt
3
@Ygg Aus den lodash-Dokumenten. "Gibt ein neues Array eindeutiger Werte in der angegebenen Reihenfolge zurück , die in einem oder mehreren Arrays vorhanden sind."
Richard Ayotte
4
Ich bevorzuge underscore.js. Was ich letztendlich verwendet habe, ist underscore.flatten(), was besser als Union ist, da es ein Array von Arrays benötigt.
Weber
8
@weaver _.flatten wird zusammengeführt, aber nicht "dupliziert".
GijsjanB
9
Schnelle Leistung gegen lodash gegen die Top-Antwort: jsperf.com/merge-two-arrays-keeping-only-unique-values
slickplaid
288

Verketten Sie zuerst die beiden Arrays und filtern Sie anschließend nur die eindeutigen Elemente heraus:

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]

Bearbeiten

Wie vorgeschlagen, besteht eine leistungsfähigere Lösung darin, die eindeutigen Elemente herauszufiltern, bbevor sie verkettet werden mit 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]

simo
quelle
5
Die ursprüngliche Lösung hier hat den Vorteil, dass Dupes in jedem Quellarray entfernt werden. Ich denke, es hängt von Ihrem Kontext ab, den Sie verwenden würden.
TheGecko
Sie können für die IE6-Unterstützung verschiedene Elemente zusammenführen: c = Array.from (neues Set (c));
Tobi G.
Wenn ich tatsächlich ändern möchte, aum hinzuzufügen b, ist es dann besser, durchzugehen und Push zu verwenden? a.forEach(function(item){ if(a.indexOf(item)<0) a.push(item); });
Ehrfurcht
1
Nur eine Erinnerung an die aktuelle Browsernutzung caniuse.com/usage-table für Leute, die sich Sorgen um IE6 machen .
pmrotule
10
@ Andrew: Noch besser: 1. var c = [...a, ...b.filter(o => !~a.indexOf(o))]; 2. var c = [...new Set([...a, ...b])];
7vujy0f0hy
203

Dies ist eine ECMAScript 6-Lösung, die Spread-Operator- und Array-Generika verwendet.

Derzeit funktioniert es nur mit Firefox und möglicherweise mit der technischen Vorschau von Internet Explorer.

Aber wenn Sie Babel verwenden , können Sie es jetzt haben.

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

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

Adria
quelle
14
Dies sollte zur akzeptierten Antwort hinzugefügt werden. Diese Lösung ist viel effizienter und eleganter als das, was derzeit möglich ist, aber es ist das, was wir unweigerlich können (und tun sollten, um auf diesem Gebiet Schritt zu halten).
EmmaGamma
Dies ist nicht ganz das Gleiche wie die Frage des OP (dies scheint eher eine Flatmap zu sein als alles andere), aber es ist positiv, weil es großartig ist.
jedd.ahyoung
4
Schwer zu sagen, dass dies die akzeptierte Antwort sein sollte, da die Frage aus dem Jahr 2009 stammt. Aber ja, dies ist nicht nur "performanter", sondern auch "elegant"
Cezar Augusto
11
Array.fromkann anstelle des Spread-Operators verwendet werden: Array.from(new Set([].concat(...arr)))
Henry Blyth
1
Das ist sehr elegant. Leider unterstützt Typescript dies noch nicht. stackoverflow.com/questions/33464504/…
Ben Carp
190

ES6

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

ODER

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

ODER

[...new Set([...array1 ,...array2])]; //   => remove duplication
Abdennour TOUMI
quelle
1
1./2. Beispiel ist überhaupt nicht union+ 1. Beispiel sprengt den Stapel für große Arrays + 3. Beispiel ist unglaublich langsam und verbraucht viel Speicher, da zwei Zwischen- Arrays erstellt werden müssen + 3. Beispiel kann nur unionmit einem bekannten verwendet werden Anzahl Arrays zur Kompilierungszeit.
Also, wie würdest du es machen?
David Noreña
14
Setist der Weg hierher
Philk
3
Beachten Sie, dass for set nicht zwei Objekte mit denselben Schlüsselwertpaaren deduplizieren kann, es sei denn, es handelt sich um dieselben Objektreferenzen.
Jun711
2
Funktioniert nicht mit einem Array von Objekten, da nur Objektreferenzen zusammengeführt werden und es egal ist, ob die Objekte selbst gleich sind.
Wilson Biggs
87

Mit einem Set (ECMAScript 2015) ist es so einfach:

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

Benny Neugebauer
quelle
7
Ich halte dies für die "Akzeptierte Antwort" für die Verwendung von ES6.
Mwieczorek
9
@mwieczorek Wie wäre es mit:const array3 = [...new Set(array1.concat(array2))]
Robby Cornelissen
5
Es funktioniert nicht, wenn Sie ein Array von Objekten verwenden
Carkod
1
zum Zusammenführen verschiedener Objekte ohne Duplizieren: stackoverflow.com/a/54134237/3131433
Rakibul Haq
38

Hier ist eine etwas andere Einstellung der Schleife. Mit einigen der Optimierungen in der neuesten Version von Chrome ist dies die schnellste Methode zum Auflösen der Vereinigung der beiden Arrays (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-Schleife: ~ 589k ops / s
Filter: ~ 445k ops / s
lodash: 308k ops / s
für Schleifen: 225k ops / s

In einem Kommentar wurde darauf hingewiesen, dass eine meiner Setup-Variablen dazu führte, dass meine Schleife den Rest überschritt, da kein leeres Array zum Schreiben initialisiert werden musste. Ich bin damit einverstanden, daher habe ich den Test auf das Spielfeld umgeschrieben und eine noch schnellere Option hinzugefügt.

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

In dieser alternativen Lösung habe ich die assoziative Array-Lösung einer Antwort kombiniert, um den .indexOf()Aufruf in der Schleife zu eliminieren, der die Dinge mit einer zweiten Schleife erheblich verlangsamte, und einige der anderen Optimierungen, die andere Benutzer vorgeschlagen haben, ebenfalls in ihre Antworten aufgenommen .

Die Top-Antwort hier mit der Doppelschleife für jeden Wert (i-1) ist immer noch deutlich langsamer. lodash ist immer noch stark und ich würde es jedem empfehlen, dem es nichts ausmacht, seinem Projekt eine Bibliothek hinzuzufügen. Für diejenigen, die nicht wollen, ist meine while-Schleife immer noch eine gute Antwort, und die Filterantwort zeigt hier eine sehr starke Leistung, die alle meine Tests mit dem neuesten Canary Chrome (44.0.2360) zum jetzigen Zeitpunkt übertrifft.

Schauen Sie sich Mikes Antwort und Dan Stockers Antwort an, wenn Sie die Geschwindigkeit steigern möchten. Dies sind bei weitem die schnellsten aller Ergebnisse, nachdem fast alle brauchbaren Antworten durchgegangen sind.

Slickplaid
quelle
Ihre Methodik weist einen Fehler auf: Sie haben die Erstellung von Array3 in die Einrichtungsphase verschoben, während diese Kosten nur Teil der Punktzahl Ihrer Lösung sein sollten. Wenn diese 1 Zeile verschoben wird , fällt Ihre Lösung auf die Geschwindigkeit der for-Schleife. Ich verstehe, dass das Array wiederverwendet werden kann, aber vielleicht könnten auch die anderen Algorithmen davon profitieren, dass nicht jeder erforderliche Baustein deklariert und initialisiert werden muss.
Doldt
Ich stimme Ihrer Prämisse @doldt zu, bin aber mit Ihren Ergebnissen nicht einverstanden. Das schleifenbasierte Entfernen von Einträgen weist einen grundlegenden Konstruktionsfehler auf, da Sie die Länge des Arrays nach dem Entfernen von Elementen erneut überprüfen müssen, was zu einer langsameren Ausführungszeit führt. Eine while-Schleife, die rückwärts arbeitet, hat diese Effekte nicht. Hier ist ein Beispiel, bei dem so viele Setup-Variablen wie möglich entfernt werden, ohne dass die ursprüngliche Antwort zu stark geändert wird
slickplaid
@slickplaid Die verknüpften Tests sind leer und die nächste Revision bei jsperf hängt in der while-Schleife.
Doldt
@doldt Ich habe Ihre Bedenken in meiner Antwort angesprochen und auch einen ordnungsgemäß aktualisierten Test hinzugefügt. Lassen Sie mich wissen, ob Sie diesen Ergebnissen zustimmen oder nicht. Außerdem habe ich mit einem assoziativen Array ein weiteres besseres Ergebnis hinzugefügt.
Slickplaid
1
@slickplaid Vielen Dank, dass Sie die erweiterte Perf-Seite eingerichtet haben. Wenn ich nichts vermisse, funktioniert die Funktion "whileLoopAlt2" nicht? Es wird ein neues Array erstellt, das das erste Array und das zweite Array enthält (in umgekehrter Reihenfolge). Um Verwirrung zu vermeiden, habe ich eine weitere Überarbeitung vorgenommen, die die fehlerhafte Funktion entfernt. Ich habe auch ein zusätzliches Beispiel hinzugefügt: jsperf.com/merge-two-arrays-keeping-only-unique-values/22
Stephen S
37

Sie können dies einfach mit ECMAScript 6 tun.

var array1 = ["Vijendra", "Singh"];
var array2 = ["Singh", "Shakya"];
var array3 = [...new Set([...array1 ,...array2])];
console.log(array3); // ["Vijendra", "Singh", "Shakya"];
  • Verwenden Sie den Spread-Operator zum Verketten des Arrays.
  • Verwenden Sie Set, um einen bestimmten Satz von Elementen zu erstellen.
  • Verwenden Sie erneut den Spread-Operator, um das Set in ein Array zu konvertieren.
Rajaprabhu Aravindasamy
quelle
2
Ich erhalte die Fehlermeldung: Typ 'Set <string>' ist kein Array-Typ.
Gattsbr
3
Und wenn Sie aus irgendeinem Grund den Spread-Operator nicht verwenden möchten, gibt es auch : Array.from(new Set(array1.concat(array2))).
kba
@gattsbr, mit Typoskript in tsconfig.json, können Sie hinzufügen "downlevelIteration": truezu 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;
};

Eine viel bessere Array-Merge-Funktion.

GAgnew
quelle
4
var test = ['a', 'b', 'c']; console.log(test); wird drucken ["a", "b", "c", merge: function]
Doubidou
Hervorragende Lösung. Ich habe den oben veröffentlichten jsperf-Test von @slickplaid ( jsperf.com/merge-two-arrays-keeping-only-unique-values/3 ) aktualisiert und es sieht so aus, als wäre dies der schnellste von ihnen.
Cobra
@Cobra Diese Antwort ist 53% langsamer als meine, da die Gefahr besteht, dass sie unter Chrome 40.0.2214 (Stand: 18.02.15) kleinlich klingt. OTOH IE11 scheint für meine Antwort überhaupt nicht optimiert zu sein. :) Chrome Mobile rockt es aber immer noch. Ehrlich gesagt, wenn Sie lodash / _ verwenden, was die meisten von uns sollten, steht die wahre Antwort bereits ganz oben auf dieser Liste. :)
Slickplaid
@slickplaid Stimmt, und es ist ziemlich viel schneller, sogar im Vergleich zum lodash / _ one. Ich werde wahrscheinlich irgendwann meine Implementierung auf etwas Ähnliches wie Ihre umstellen. : D
Cobra
1
Ich bin mir nicht sicher, wie hoch die Kosten für die indexOf () -Methode sind, aber dies ist wahrscheinlich die schnellste ES5-kompatible Methode. Auch nichts wert, dass die variable Länge der Argumente nicht benötigt wird. Diese Methode ist verkettbar. @slickplaid Das Laden einer Bibliothek ist niemals eine Antwort auf die Frage "Wie geht das in Javascript?". Sicherlich haben viele Bibliotheken eine Funktion, um diesen 7-Zeilen-Job zu erledigen.
Dehart
19

Ich werfe nur meine zwei Cent hinein.

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

Dies ist eine Methode, die ich häufig verwende. Sie verwendet ein Objekt als Hash-Lookup-Tabelle, um die doppelte Überprüfung durchzuführen. Unter der Annahme, dass der Hash O (1) ist, läuft dies in O (n), wobei n a.length + b.length ist. Ich habe ehrlich gesagt keine Ahnung, wie der Browser den Hash ausführt, aber er funktioniert gut bei vielen tausend Datenpunkten.

Mike
quelle
Sehr schön gemacht. Schlägt alle (wenn nicht alle) anderen Ergebnisse auf dieser Seite aus, indem das assoziative Array genutzt und die Schleifen von indexOf und anderen Operationen vermieden werden. jsperf.com/merge-two-arrays-keeping-only-unique-values/21
slickplaid
Ihr "Hash" ist die String()Funktion in Javascript. Dies funktioniert möglicherweise für primitive Werte (allerdings bei Kollisionen zwischen Typen), eignet sich jedoch nicht für Arrays von Objekten.
Bergi
Ich verwende eine ähnliche Lösung. Ich erlaube die Übergabe einer HashCode-Funktion oder die Übergabe einer Zeichenfolge, um eine Eigenschaft im Objekt zu identifizieren, die als Hash-Schlüssel verwendet werden soll.
Robert Baker
19

Vermeiden Sie einfach verschachtelte Schleifen (O (n ^ 2)) und .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);
}
Dan Stocker
quelle
2
Das ist ziemlich erstaunlich, besonders wenn du Streicher machst. Zahlen würden einen zusätzlichen Schritt benötigen, um sie als solche zu behalten. Diese Funktion übertrifft alle anderen Optionen erheblich, wenn Sie nichts dagegen haben (oder sich darum kümmern), dass nach Abschluss alles eine Zeichenfolge ist. Gut gemacht. Leistungsergebnisse hier: jsperf.com/merge-two-arrays-keeping-only-unique-values/21
slickplaid
18

Vereinfachte das Beste aus dieser Antwort und verwandelte sie in eine nette Funktion:

function mergeUnique(arr1, arr2){
    return arr1.concat(arr2.filter(function (item) {
        return arr1.indexOf(item) === -1;
    }));
}
Andrew
quelle
2
Ich glaube, das ist viel sauberer als die akzeptierte Antwort. Es sieht auch so aus, als ob Filter in ECMAScript 5.1 + unterstützt werden, was jetzt ziemlich unterstützt wird.
Tom Fobear
Dies hätte akzeptiert werden sollen
Wallop
das ist so viel prägnanter.
Mox
15

Warum benutzt du kein Objekt? Es sieht so aus, als würden Sie versuchen, ein Set zu modellieren. Dadurch wird die Reihenfolge jedoch nicht beibehalten.

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
}
Nick Retallack
quelle
Meinst du nicht if (!set1.hasOwnProperty(key))?
Gumbo
2
Warum sollte ich das so meinen? Der Zweck dieser Bedingung besteht darin, Eigenschaften zu ignorieren, die möglicherweise im Prototyp des Objekts enthalten sind.
Nick Retallack
12

Die beste Lösung...

Sie können direkt in der Browserkonsole einchecken, indem Sie auf ...

Ohne Duplikat

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

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

Mit Duplikat

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

Wenn Sie ohne Duplikat möchten, können Sie von hier aus eine bessere Lösung ausprobieren - Shouting Code .

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

Probieren Sie die Chrome-Browserkonsole aus

 f12 > console

Ausgabe:

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

[1, 2, 3, "prince"]
Zigri2612
quelle
Es werden keine Duplikate aus dem Ausgabearray entfernt.
Shahar
9

Mein anderthalb Cent:

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);
Held Qu
quelle
Es wird nichts Neues in ES6 verwendet. Habe ich etwas verpasst?
Bergi
@Bergi: Ja, du hast recht. Vielen Dank für die Notiz. Irgendwie habe ich mit diesem Skript gespielt und wahrscheinlich gab es eine Version mit ES6-Funktion, aber jetzt enthält es indexOf, das es seit Jahrhunderten gibt. Mein Fehler, sorry.
Hero Qu
8

Sie können dies einfach mit Underscore.js erreichen => uniq :

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

console.log(array3)

Es wird gedruckt ["Vijendra", "Singh", "Shakya"] .

Mohideen bin Mohammed
quelle
7

Für ES6 nur eine Zeile:

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

Ich weiß, dass es bei dieser Frage nicht um eine Reihe von Objekten geht, aber Suchende landen hier.

Daher lohnt es sich, zukünftigen Lesern eine geeignete ES6-Methode zum Zusammenführen und anschließenden Entfernen von Duplikaten hinzuzufügen

Array von Objekten :

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} ]
Stavm
quelle
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
  }

Die Implementierung der indexOfMethode für andere Browser erfolgt über MDC

Amarghosh
quelle
1
Ich konnte es in w3schools nicht finden, deshalb habe ich es geschrieben. w3schools.com/jsref/jsref_obj_array.asp Benötigt es fromübrigens einen Parameter?
Amarghosh
Danke @Gumbo und @meder - ich werde jetzt meine Lesezeichen ändern. Ich muss noch etwas Ernstes in js tun und ich benutze w3schools als Gelegenheitsreferenz (das ist alles, was ich jemals gebraucht habe) - vielleicht habe ich das deshalb nicht bemerkt.
Amarghosh
Laut MDC erfordert indexOf Javascript 1.6. Wäre es sicher anzunehmen, dass die gängigen Browser (> = FF2,> IE6 usw.) dies unterstützen würden?
Amarghosh
4
IE6 unterstützt Array.prototype.indexOf nicht. Fügen Sie einfach die von Mozilla angegebene Unterstützungsmethode ein, damit der IE keinen Fehler auslöst.
Meder Omuraliev
aktualisiert mit indexOf. Bereinigte den Code durch Entfernen des kommentierten Teils. @meder - nochmals vielen Dank.
Amarghosh
6

Neue Lösung (die verwendet Array.prototype.indexOfund 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 )
};

Verwendungszweck:

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

Array.prototype.indexOf (für Internet Explorer):

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;
  };
meder omuraliev
quelle
@Mender: Wenn die Reihenfolge keine Rolle spielt, wie ich das mache
Vijjendra
1
Es ist keine Standard-ECMAScript-Methode, die für Array.prototype definiert wurde. Ich bin mir jedoch bewusst, dass Sie sie problemlos für IE und andere Browser definieren können, die sie nicht unterstützen.
Meder Omuraliev
Beachten Sie, dass dieser Algorithmus O (n ^ 2) ist.
Gumbo
Welcher Algorithmus ist Ihre Antwort?
Meder Omuraliev
@meder: Mein Algorithmus ist ein Vereinigungsalgorithmus. Die Vereinigung selbst erfolgt in O (n + m), die Sortierung dauert jedoch höchstens O (n · log n + m · log m). Der gesamte Algorithmus ist also O (n · log n + m · log m).
Gumbo
6

Dies kann mit Set erfolgen.

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>

Karan Singla
quelle
6

Es gibt so viele Lösungen zum Zusammenführen von zwei Arrays. Sie können in zwei Hauptkategorien unterteilt werden (mit Ausnahme der Verwendung von Bibliotheken von Drittanbietern wie lodash oder underscore.js).

a) Kombinieren Sie zwei Arrays und entfernen Sie doppelte Elemente.

b) Filtern Sie Elemente heraus, bevor Sie sie kombinieren.

Kombinieren Sie zwei Arrays und entfernen Sie doppelte Elemente

Kombinieren

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

Vereinigend

Es gibt viele Möglichkeiten, ein Array zu vereinheitlichen. Ich persönlich schlage unten zwei Methoden vor.

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

Filtern Sie Elemente heraus, bevor Sie sie kombinieren

Es gibt auch viele Möglichkeiten, aber ich persönlich schlage den folgenden Code aufgrund seiner Einfachheit vor.

const merged = array1.concat(array2.filter(secItem => !array1.includes(secItem)));
TopW3
quelle
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]
Lajos Meszaros
quelle
5
array1.concat(array2).filter((value, pos, arr)=>arr.indexOf(value)===pos)

Das Schöne an diesem ist die Leistung und dass Sie bei der Arbeit mit Arrays im Allgemeinen Verkettungsmethoden wie Filter, Map usw. verwenden, damit Sie diese Zeile hinzufügen können und Array2 mit Array1 verknüpft und dedupliziert wird, ohne dass ein Verweis auf das spätere erforderlich ist eine (wenn Sie Methoden verketten, die Sie nicht haben), Beispiel:

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

(Ich mag es nicht, Array.prototype zu verschmutzen, und das wäre der einzige Weg, die Kette zu respektieren - das Definieren einer neuen Funktion wird sie brechen - also denke ich, dass so etwas der einzige Weg ist, dies zu erreichen.)

Cancerbero
quelle
4

Sie können dies versuchen:

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

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

mitesh7172
quelle
3

Ein funktionaler Ansatz mit ES2015

Nach dem funktionalen Ansatz ist a unionvon zwei Arrays nur die Zusammensetzung von concatund filter. Um eine optimale Leistung zu erzielen, greifen wir auf den nativen SetDatentyp zurück, der für die Suche nach Eigenschaften optimiert ist.

Wie auch immer, die Schlüsselfrage in Verbindung mit einer unionFunktion ist, wie Duplikate behandelt werden. Folgende Permutationen sind möglich:

Array A      + Array B

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

Die ersten beiden Permutationen sind mit einer einzigen Funktion einfach zu handhaben. Die letzten beiden sind jedoch komplizierter, da Sie sie nicht verarbeiten können, solange Sie sich auf SetSuchvorgänge verlassen. Da das Wechseln zu einfachen ObjectSuchvorgängen für alte Eigenschaften einen schwerwiegenden Leistungseinbruch bedeuten würde, ignoriert die folgende Implementierung nur die dritte und vierte Permutation. Sie müssten eine separate Version von erstellen union, um sie zu unterstützen.


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

Von hier an wird es trivial, eine unionnFunktion zu implementieren , die eine beliebige Anzahl von Arrays akzeptiert (inspiriert von Naomiks Kommentaren):

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

Es stellt sich heraus, dass unionnes nur foldl(aka Array.prototype.reduce) ist, was unionals Reduzierer dient. Hinweis: Da die Implementierung keinen zusätzlichen Akkumulator verwendet, wird ein Fehler ausgegeben, wenn Sie ihn ohne Argumente anwenden.


quelle
1
ein paar Rückmeldungen: Ich habe das bemerkt flipund bin notfunbenutzt. Auch unionByPrädikat Lecks Implementierungsdetails (erfordern implizites Wissen von SetTyp). Es wäre schön, wenn Sie so etwas tun könnten: union = unionBy (apply)und unionci = unionBy (p => x => p(x.toLowerCase())). Auf diese Weise sendet der Benutzer einfach, was auch immer der Gruppierungswert ist p- nur eine Idee ^ _ ^
Danke
zsVariablendeklaration fehlt auch var/ letSchlüsselwort
Danke
1
Hier ist ein Code-Snippet zur Verdeutlichung [gist: unionBy.js ]
Danke
@naomik Nachdem ich meine Lösung eine Weile überdacht habe, bin ich mir nicht mehr so ​​sicher, ob es der richtige Weg ist, das Prädikat zu übergeben. Alles, was Sie gewinnen, ist eine Transformation jedes Elements des zweiten Arrays. Ich frage mich, ob dieser Ansatz mehr als nur Spielzeugprobleme löst.
3

deswegen ... hier ist eine einzeilige Lösung:

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

Nicht besonders lesbar, aber es kann jemandem helfen:

  1. Wendet eine Reduzierungsfunktion an, bei der der anfängliche Akkumulatorwert auf ein leeres Array gesetzt ist.
  2. Die Reduktionsfunktion verwendet concat, um jedes Subarray an das Akkumulatorarray anzuhängen.
  3. Das Ergebnis wird als Konstruktorparameter übergeben, um einen neuen zu erstellen Set.
  4. Der Spread-Operator wird verwendet, um das Setin ein Array zu konvertieren .
  5. Die sort()Funktion wird auf das neue Array angewendet.
Mark Tyers
quelle
2
Auch anstelle von können reduce()Sie verwendenArray.from(set)
Eran Goldin
3

Einzelne oder mehrere Array-Eingänge zusammenführen oder zusammenführen und deDuplizieren. Beispiel unten.

Verwenden von ES6 - Festlegen der Destrukturierung

Ich habe diese einfache Funktion geschrieben, die mehrere Array-Argumente akzeptiert. Hat so ziemlich das gleiche wie die obige Lösung, hat nur einen praktischeren Anwendungsfall. Diese Funktion verkettet doppelte Werte nicht nur in einem Array, damit sie zu einem späteren Zeitpunkt gelöscht werden können.

KURZFUNKTIONSDEFINITION (nur 9 Zeilen)

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

VERWENDUNGSBEISPIEL 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]
DevWL
quelle
Warum arr.maphier verwenden? Sie verwenden es als foreach, da das Ergebnis ignoriert wird
Antony
Ich habe return Array.from (set.values ​​()) verwendet. , weil vscode einen Fehler bei der Rückgabe [... set] gibt;
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]
Bharti Ladumor
quelle
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));

Shiva
quelle