Twee arrays in JavaScript samenvoegen en items dedupliceren

Ik heb twee JavaScript-arrays:

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

Ik wil dat de uitvoer is:

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

De uitvoerarray zou herhaalde woorden moeten hebben verwijderd.

Hoe voeg ik twee arrays in JavaScript samen zodat ik alleen de unieke items van elke array krijg in dezelfde volgorde als waarin ze in de originele arrays zijn ingevoegd?


Antwoord 1, autoriteit 100%

Om de arrays gewoon samen te voegen (zonder duplicaten te verwijderen)

ES5-versie gebruikt Array.concat:

var array1 = ["Vijendra", "Singh"];
var array2 = ["Singh", "Shakya"];
console.log(array1.concat(array2));

Antwoord 2, autoriteit 32%

Met Underscore.js of Lo-Dash kunt u het volgende doen:

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>

Antwoord 3, autoriteit 18%

Voeg eerst de twee arrays samen, filter vervolgens alleen de unieke items eruit:

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]

Antwoord 4, autoriteit 14%

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

OF

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

Antwoord 5, autoriteit 13%

Dit is een ECMAScript 6-oplossing die de spread-operator gebruikt en array-generieken.

Momenteel werkt het alleen met Firefox, en mogelijk Internet Explorer Technical Preview.

Maar als je Babel gebruikt, kun je het nu hebben.

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

Antwoord 6, autoriteit 6%

Een Set gebruiken (ECMAScript 2015 ), zal het zo simpel zijn:

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

Antwoord 7, autoriteit 2%

Hier is een iets andere kijk op de lus. Met enkele van de optimalisaties in de nieuwste versie van Chrome is dit de snelste methode om de unie van de twee arrays op te lossen (Chrome 38.0.2111).

http://jsperf.com/merge-two-arrays- alleen-unieke-waarden behouden

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

terwijl-lus: ~589k ops/s
filter: ~445k ops/s
lodash: 308k ops/s
voor loops: 225k ops/s

Een opmerking wees erop dat een van mijn setup-variabelen ervoor zorgde dat mijn lus voorliep op de rest, omdat het geen lege array hoefde te initialiseren om naar te schrijven. Daar ben ik het mee eens, dus ik heb de test herschreven om het speelveld gelijk te maken, en een nog snellere optie toegevoegd.

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 deze alternatieve oplossing heb ik de associatieve array-oplossing van één antwoord gecombineerd om de .indexOf()-aanroep in de lus te elimineren, wat de zaken veel vertraagde met een tweede lus, en een aantal van de andere optimalisaties die andere gebruikers ook in hun antwoorden hebben voorgesteld.

Het beste antwoord hier met de dubbele lus op elke waarde (i-1) is nog steeds aanzienlijk langzamer. lodash doet het nog steeds goed, en ik zou het nog steeds aanraden aan iedereen die het niet erg vindt om een ​​bibliotheek aan hun project toe te voegen. Voor degenen die dat niet willen, mijn while-lus is nog steeds een goed antwoord en het filterantwoord heeft hier een zeer sterke weergave, en overtreft al mijn tests met de nieuwste Canary Chrome (44.0.2360) vanaf dit moment.

Bekijk Mike’s antwoord en Het antwoord van Dan Stocker als je een tandje bij wilt zetten. Dat zijn verreweg de snelste van alle resultaten na het doornemen van bijna alle haalbare antwoorden.


Antwoord 8, autoriteit 2%

Je kunt het eenvoudig doen met ECMAScript 6,

var array1 = ["Vijendra", "Singh"];
var array2 = ["Singh", "Shakya"];
var array3 = [...new Set([...array1 ,...array2])];
console.log(array3); // ["Vijendra", "Singh", "Shakya"];
  • Gebruik de spread-operator om de array samen te voegen .
  • Gebruik Set om een ​​aparte set van elementen.
  • Gebruik opnieuw de spread-operator om de Set om te zetten in een array.

Antwoord 9, autoriteit 2%

Ik heb het beste van dit antwoord vereenvoudigd en er een leuke functie van gemaakt:

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

Antwoord 10

Blijf gewoon uit de buurt van geneste lussen (O(n^2)) en .indexOf() (+O(n)).

function merge(a, b) {
  var hash = {};
  var 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);
}
var array1 = ["Vijendra", "Singh"];
var array2 = ["Singh", "Shakya"];
var array3 = merge(array1, array2);
console.log(array3);

Antwoord 11

Ik gooi er even mijn twee cent in.

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

Dit is een methode die ik veel gebruik, het gebruikt een object als een hashlookup-tabel om de dubbele controle uit te voeren. Ervan uitgaande dat de hash O(1) is, dan loopt dit in O(n) waarbij n a.length + b.length is. Ik heb eerlijk gezegd geen idee hoe de browser de hash doet, maar hij presteert goed op vele duizenden datapunten.


Antwoord 12

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

Een veel betere functie voor het samenvoegen van arrays.


Antwoord 13

BEWERKEN:

De eerste oplossing is alleen de snelste als er weinig items zijn. Als er meer dan 400 items zijn, wordt de oplossing Set de snelste. En als er 100.000 items zijn, is het duizend keer sneller dan de eerste oplossing.

Aangezien prestaties alleen belangrijk zijn als er veel items zijn en dat de Set-oplossing verreweg het meest leesbaar is, zou dit in de meeste gevallen de juiste oplossing moeten zijn

De onderstaande prestatieresultaten zijn berekend met een klein aantal items


Gebaseerd op jsperf, is de snelste manier (edit: als er minder dan 400 items zijn) om twee arrays samen te voegen tot een nieuwe:

for (var i = 0; i < array2.length; i++)
    if (array1.indexOf(array2[i]) === -1)
      array1.push(array2[i]);

Deze is 17% langzamer:

array2.forEach(v => array1.includes(v) ? null : array1.push(v));

Deze is 45% langzamer (edit: als er minder dan 100 items zijn. Het is een stuk sneller als er veel items zijn):

var a = [...new Set([...array1 ,...array2])];

En de geaccepteerde antwoorden zijn 55% langzamer (en veel langer om te schrijven) (edit: en het is enkele orde van grootte langzamer dan alle andere methoden als er 100.000 items zijn)

var a = array1.concat(array2);
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);
    }
}

https://jsperf.com/merge-2-arrays-without-duplicate


Antwoord 14

Waarom gebruik je geen object? Het lijkt erop dat je een set probeert te modelleren. Hierdoor blijft de bestelling echter niet behouden.

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
}

Antwoord 15

De beste oplossing…

U kunt rechtstreeks in de browserconsole inchecken door op…

. te klikken

Zonder duplicaat

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

Met duplicaat

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

Als je wilt zonder duplicaat, kun je hier een betere oplossing proberen – Schreeuwcode.

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

Probeer het op de Chrome-browserconsole

 f12 > console

Uitvoer:

["prince", "asish", 5, "ravi", 4]
[1, 2, 3, "prince"]

Antwoord 16

Ik weet dat deze vraag niet over een reeks objecten gaat, maar zoekers komen hier wel terecht.

het is dus de moeite waard om voor toekomstige lezers een goede ES6-manier toe te voegen voor het samenvoegen en vervolgens verwijderen van duplicaten

array van objecten:

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

Antwoord 17

Prestaties

Vandaag 2020.10.15 voer ik tests uit op MacOs HighSierra 10.13.6 op Chrome v86, Safari v13.1.2 en Firefox v81 voor gekozen oplossingen.

Resultaten

Voor alle browsers

  • oplossing H is snel/snelst
  • oplossingen L is snel
  • oplossing D is het snelst op chrome voor grote arrays
  • oplossing G is snel op kleine arrays
  • oplossing M is het langzaamst voor kleine arrays
  • oplossingen E zijn het langzaamst voor grote arrays

voer hier de afbeeldingsbeschrijving in

Details

Ik voer 2 testgevallen uit:

  • voor arrays met 2 elementen – u kunt het HIER
  • uitvoeren

  • voor arrays van 10.000 elementen – u kunt het HIER
  • uitvoeren

over oplossingen
A,
B,
C,
D,
E,
G,
H,
J,
L,
M
weergegeven in onderstaand fragment


Antwoord 18

Voor ES6, slechts één regel:

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

Antwoord 19

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

Antwoord 20

U kunt dit eenvoudig bereiken met Underscore.js’s => uniq:

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

Het zal [“Vijendra”, “Singh”, “Shakya”] afdrukken.


Antwoord 21

Er zijn zoveel oplossingen om twee arrays samen te voegen.
Ze kunnen worden onderverdeeld in twee hoofdcategorieën (behalve het gebruik van bibliotheken van derden zoals lodash of underscore.js).

a) combineer twee arrays en verwijder dubbele items.

b) filter items uit voordat je ze combineert.

Combineer twee arrays en verwijder dubbele items

Combineren

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

Verenigen

Er zijn veel manieren om een ​​array te verenigen, ik stel persoonlijk de onderstaande twee methoden voor.

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

Filter items uit voordat je ze combineert

Er zijn ook veel manieren, maar ik raad persoonlijk de onderstaande code aan vanwege de eenvoud.

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

Antwoord 22

Het kan gedaan worden met 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>

Antwoord 23

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

Implementatie van de indexOf-methode voor andere browsers is afkomstig van MDC


Antwoord 24

Nieuwe oplossing (die gebruikmaakt van Array.prototype.indexOf en 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 )
};

Gebruik:

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

Array.prototype.indexOf (voor 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;
  };

Antwoord 25

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]

Antwoord 26

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

Het leuke van deze is de prestatie en dat je in het algemeen, wanneer je met arrays werkt, methodes zoals filter, map, etc aan elkaar koppelt, zodat je die regel kunt toevoegen en het array2 zal concateren en dedupliceren met array1 zonder dat er een verwijzing nodig is naar de laatste (wanneer je methoden koppelt die je niet hebt), bijvoorbeeld:

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

(Ik hou er niet van om Array.prototype te vervuilen en dat zou de enige manier zijn om de keten te respecteren – het definiëren van een nieuwe functie zal het breken – dus ik denk dat zoiets als dit de enige manier is om dat te bereiken)

p>


Antwoord 27

Een functionele benadering met ES2015

Volgens de functionele benadering is een union van twee Arrays slechts de samenstelling van concat en filter. Om optimale prestaties te leveren, gebruiken we het native gegevenstype Set, dat is geoptimaliseerd voor het opzoeken van eigenschappen.

Hoe dan ook, de belangrijkste vraag in combinatie met een union-functie is hoe duplicaten moeten worden behandeld. De volgende permutaties zijn mogelijk:

Array A      + Array B
[unique]     + [unique]
[duplicated] + [unique]
[unique]     + [duplicated]
[duplicated] + [duplicated]

De eerste twee permutaties zijn gemakkelijk te verwerken met een enkele functie. De laatste twee zijn echter ingewikkelder, omdat u ze niet kunt verwerken zolang u vertrouwt op Set-zoekopdrachten. Aangezien het overschakelen naar gewoon oude Object eigenschapszoekopdrachten een serieuze prestatiehit zou opleveren, negeert de volgende implementatie gewoon de derde en vierde permutatie. Je zou een aparte versie van union moeten bouwen om ze te ondersteunen.


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

Antwoord 28

DeDuplicate enkele of Merge en DeDuplicate meerdere array-ingangen. Voorbeeld hieronder.

gebruik van ES6 – Set, for of, destructuring

Ik heb deze eenvoudige functie geschreven die meerdere arrayargumenten nodig heeft.
Doet vrijwel hetzelfde als de bovenstaande oplossing, het heeft alleen meer praktische use-case. Deze functie voegt geen dubbele waarden samen tot één array, zodat ze ze in een later stadium kunnen verwijderen.

KORTE FUNCTIEDEFINITIE (slechts 9 regels)

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

GEBRUIK VOORBEELD 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]

Antwoord 29

Je kunt dit proberen:

const union = (a, b) => Array.from(new Set([...a, ...b]));
console.log(union(["neymar","messi"], ["ronaldo","neymar"]));

Antwoord 30

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

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Other episodes