Comment fusionner deux tableaux en JavaScript et supprimer les éléments dupliqués
j'ai deux tableaux JavaScript:
var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];
je veux que la sortie soit:
var array3 = ["Vijendra","Singh","Shakya"];
le tableau de sortie doit avoir des mots répétés supprimés.
comment fusionner deux tableaux en JavaScript de sorte que je n'obtienne que les éléments uniques de chaque tableau dans le même ordre qu'ils ont été insérés dans les tableaux originaux?
30 réponses
juste fusionner les tableaux (sans la suppression des doublons)
version ES5 use Array.concat
:
var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];
var array3 = array1.concat(array2); // Merges both arrays
// [ 'Vijendra', 'Singh', 'Singh', 'Shakya' ]
ES6 version utiliser déstructuration
const array1 = ["Vijendra","Singh"];
const array2 = ["Singh", "Shakya"];
const array3 = [...array1, ...array2];
Puisqu'il n'y a pas de moyen "intégré" pour supprimer les doublons ( ECMA-262 a effectivement Array.forEach
ce qui serait génial pour cela), nous devons le faire manuellement:
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;
};
Puis, pour l'utiliser:
var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];
// Merges both arrays and gets unique items
var array3 = array1.concat(array2).unique();
cela préservera également l'ordre des tableaux (I. e, Pas de tri nécessaire).
comme beaucoup de gens sont ennuyés par l'augmentation prototype de Array.prototype
et for in
boucles, voici une façon moins invasive de l'utiliser:
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));
pour ceux qui ont la chance de travailler avec des navigateurs où ES5 est disponible, vous pouvez utiliser Object.defineProperty
comme ceci:
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;
}
});
Avec Underscore.js ou Lo-Dash vous pouvez faire:
_.union([1, 2, 3], [101, 2, 1, 10], [2, 1]);
=> [1, 2, 3, 101, 10]
d'abord concaténer les deux tableaux, ensuite filtrer seulement les éléments uniques.
var a = [1, 2, 3], b = [101, 2, 1, 10];
var c = a.concat(b);
var d = c.filter(function (item, pos) {return c.indexOf(item) == pos});
// d is [1,2,3,101,10]
http://jsfiddle.net/simo/98622 /
Modifier
comme suggéré par @Dmitry (voir le deuxième commentaire ci-dessous) une solution plus performante serait de filtrer les éléments uniques dans b
avant de concaténer avec a
var a = [1, 2, 3], b = [101, 2, 1, 10];
var c = a.concat(b.filter(function (item) {
return a.indexOf(item) < 0;
}));
// d is [1,2,3,101,10]
il s'agit d'une solution ECMAScript 6 utilisant spread operator et des génériques array array.
Actuellement, il ne fonctionne avec Firefox, et peut-être Internet Explorer Aperçu technique.
Mais si vous utilisez Babel , vous pouvez l'avoir maintenant.
// Input: [ [1, 2, 3], [101, 2, 1, 10], [2, 1] ]
// Output: [1, 2, 3, 101, 10]
function mergeDedupe(arr)
{
return [...new Set([].concat(...arr))];
}
ES6
array1.push(...array2) // => don't remove duplication
ou
[...array1,...array2] // => don't remove duplication
ou
[...new Set([...array1 ,...array2])]; // => remove duplication
voici un point de vue légèrement différent sur la boucle. Avec certaines des optimisations de la dernière version de Chrome, C'est la méthode la plus rapide pour résoudre l'union des deux tableaux (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 loop: ~589k ops /s
1519110920"
filtre: ~445k ops / s
lodash: 308k ops/s
pour les boucles: 225K ops / s
un commentaire a fait remarquer que l'une de mes variables de configuration faisait que ma boucle devançait le reste, parce qu'elle n'avait pas besoin d'initialiser un tableau vide pour écrire. Je suis d'accord avec cela, donc j'ai réécrit le test pour égaliser le terrain de jeu, et inclus une option encore plus rapide.
http://jsperf.com/merge-two-arrays-keeping-only-unique-values/21
var whileLoopAlt = function(array1, array2) {
var array3 = [];
var arr = array1.concat(array2);
var len = arr.length;
var assoc = {};
while(len--) {
var itm = arr[len];
if(!assoc[itm]) { // Eliminate the indexOf call
array3.unshift(itm);
assoc[itm] = true;
}
}
return array3;
};
dans cette solution alternative, j'ai combiné la solution associative array d'une réponse pour éliminer l'appel .indexOf()
dans la boucle qui ralentissait les choses beaucoup avec une deuxième boucle, et inclus certaines des autres optimisations que d'autres utilisateurs ont suggéré dans leurs réponses aussi bien.
la réponse supérieure ici avec la double boucle sur chaque valeur (i-1) est encore beaucoup plus lente. lodash fait toujours fort, et je le recommande toujours à tous ceux qui ça ne dérange pas d'ajouter une bibliothèque à leur projet. Pour ceux qui ne veulent pas, ma boucle de temps est encore une bonne réponse et la réponse de filtre a une très forte exposition ici, battre sur tous mes tests avec le dernier Canary Chrome (44.0.2360) à partir de cette écriture.
Check out réponse de Mike et Dan Stocker la réponse de si vous voulez monter d'un cran dans la vitesse. Ce sont de loin le plus rapide de tous les résultats après presque toutes les réponses viables.
en utilisant un Set (ECMAScript 2015), il sera aussi simple que cela:
const array1 = ["Vijendra", "Singh"];
const array2 = ["Singh", "Shakya"];
const array3 = Array.from(new Set(array1.concat(array2)));
vous pouvez le faire simplement avec ECMAScript 6,
var array1 = ["Vijendra", "Singh"];
var array2 = ["Singh", "Shakya"];
var array3 = [...new Set([...array1 ,...array2])];
console.log(array3); // ["Vijendra", "Singh", "Shakya"];
- utilisez le spread operator pour concaténer le tableau.
- Utiliser Set pour la création d'un ensemble distinct d'éléments.
- utilisez de nouveau l'opérateur spread pour convertir l'ensemble en tableau.
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;
};
une bien meilleure fonction de fusion de tableaux.
je rajoute juste mes deux cents.
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;
}
c'est une méthode que j'utilise beaucoup, elle utilise un objet comme table hashlookup pour faire la vérification en double. En supposant que le hachage est O(1), alors cela va dans O (n) où n est a. longueur + B. longueur. Honnêtement, je n'ai aucune idée de comment le navigateur fait le hachage, mais il fonctionne bien sur des milliers de points de données.
Pourquoi n'utilisez-vous pas un objet? Il semble que vous essayez de modéliser un ensemble. Ce ne sera pas conserver l'ordre, cependant.
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
}
juste éviter les boucles emboîtées (O (N^2)), et .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);
}
mon Un penny et demi:
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);
Simplifiée simo réponse et l'a transformé en une belle fonction.
function mergeUnique(arr1, arr2){
return arr1.concat(arr2.filter(function (item) {
return arr1.indexOf(item) === -1;
}));
}
la meilleure solution...
vous pouvez vérifier directement dans la console du navigateur en appuyant sur...
sans duplicata
a = [1, 2, 3];
b = [3, 2, 1, "prince"];
a.concat(b.filter(function(el) {
return a.indexOf(el) === -1;
}));
avec duplicata
["prince", "asish", 5].concat(["ravi", 4])
si vous voulez sans dupliquer vous pouvez essayer une meilleure solution d'ici - code criant .
[1, 2, 3].concat([3, 2, 1, "prince"].filter(function(el) {
return [1, 2, 3].indexOf(el) === -1;
}));
Essayer sur Chrome, le navigateur de la console
f12 > console
Sortie:
["prince", "asish", 5, "ravi", 4]
[1, 2, 3, "prince"]
//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
}
mise en œuvre de la méthode indexOf
pour les autres navigateurs est tiré de MDC
cela peut être fait en utilisant 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>
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]
vous pouvez le réaliser simplement en utilisant le soulignement.js's = > uniq :
array3 = _.uniq(array1.concat(array2))
console.log(array3)
Il va imprimer ["Vijendra", "Singh", "Shakya"] .
array1.concat(array2).filter((value, pos, arr)=>arr.indexOf(value)===pos)
la bonne chose à propos de celui-ci est la performance et que vous en général, lorsque vous travaillez avec des tableaux, sont des méthodes de chaînage comme filtre, carte, etc donc vous pouvez ajouter cette ligne et il va concatter et deduplicate array2 avec array1 sans avoir besoin d'une référence à la dernière (lorsque vous êtes des méthodes de chaînage que vous n'avez pas), exemple:
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
(je n'aime pas polluer Tableau.prototype et ce serait la seule façon de respecter la chaîne-définir un nouvelle fonction pause - donc je pense que quelque chose comme cela, c'est la seule façon de faire cela)
nouvelle solution (qui utilise Array.prototype.indexOf
et 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 )
};
Utilisation:
>>> ['Vijendra', 'Singh'].uniqueMerge(['Singh', 'Shakya'])
["Vijendra", "Singh", "Shakya"]
tableau.prototype.indexOf (pour 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;
};
Dans Le Dojo De 1,6+
var unique = [];
var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];
var array3 = array1.concat(array2); // Merged both arrays
dojo.forEach(array3, function(item) {
if (dojo.indexOf(unique, item) > -1) return;
unique.push(item);
});
mise à Jour
voir code de travail.
fusionner un nombre illimité de tableaux ou de non-tableaux et le garder unique:
function flatMerge() {
return Array.prototype.reduce.call(arguments, function (result, current) {
if (!(current instanceof Array)) {
if (result.indexOf(current) === -1) {
result.push(current);
}
} else {
current.forEach(function (value) {
console.log(value);
if (result.indexOf(value) === -1) {
result.push(value);
}
});
}
return result;
}, []);
}
flatMerge([1,2,3], 4, 4, [3, 2, 1, 5], [7, 6, 8, 9], 5, [4], 2, [3, 2, 5]);
// [1, 2, 3, 4, 5, 7, 6, 8, 9]
flatMerge([1,2,3], [3, 2, 1, 5], [7, 6, 8, 9]);
// [1, 2, 3, 5, 7, 6, 8, 9]
flatMerge(1, 3, 5, 7);
// [1, 3, 5, 7]
en supposant que les tableaux originaux n'ont pas besoin de dé-duplication, cela devrait être assez rapide, conserver l'ordre original, et ne modifie pas les tableaux originaux...
function arrayMerge(base, addendum){
var out = [].concat(base);
for(var i=0,len=addendum.length;i<len;i++){
if(base.indexOf(addendum[i])<0){
out.push(addendum[i]);
}
}
return out;
}
utilisation:
var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];
var array3 = arrayMerge(array1, array2);
console.log(array3);
//-> [ 'Vijendra', 'Singh', 'Shakya' ]
une approche fonctionnelle avec ES2015
suivant l'approche fonctionnelle un union
de deux Array
s est juste la composition de concat
et filter
. Afin de fournir des performances optimales, nous recourons au type de données natif Set
, qui est optimisé pour les recherches de propriétés.
quoi qu'il en soit, la question clé en conjonction avec une fonction union
est de savoir comment traiter les doublons. Les permutations suivantes sont possible:
Array A + Array B
[unique] + [unique]
[duplicated] + [unique]
[unique] + [duplicated]
[duplicated] + [duplicated]
les deux premières permutations sont faciles à manipuler avec une seule fonction. Cependant, les deux derniers sont plus compliqués, puisque vous ne pouvez pas les traiter aussi longtemps que vous comptez sur des recherches Set
. Étant donné que le fait de passer à une simple ancienne recherche de propriété Object
entraînerait une performance importante, l'implémentation suivante ne tient pas compte de la troisième et de la quatrième permutation. Vous devriez construire une version séparée de union
pour les soutenir.
// 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) );
à partir de là, il devient trivial de mettre en œuvre une fonction unionn
, qui accepte n'importe quel nombre de tableaux (inspiré par les commentaires de 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) );
il s'avère que unionn
est juste foldl
(alias Array.prototype.reduce
), qui prend union
comme son réducteur. Remarque: Depuis la mise en œuvre n'est pas une accumulateur, il renvoie une erreur lorsque vous l'appliquez, sans arguments.
la façon la plus simple de faire cela est soit d'utiliser concat()
pour fusionner les tableaux et ensuite utiliser filter()
pour supprimer les doublons, ou d'utiliser concat()
et puis mettre le tableau fusionné dans un Set()
.
Première manière:
const firstArray = [1,2, 2];
const secondArray = [3,4];
// now lets merge them
const mergedArray = firstArray.concat(secondArray); // [1,2,2,3,4]
//now use filter to remove dups
const removeDuplicates = mergedArray.filter((elem, index) => mergedArray.indexOf(elem) === index); // [1,2,3, 4]
Seconde manière (mais avec les performances des implications sur l'INTERFACE utilisateur):
const firstArray = [1,2, 2];
const secondArray = [3,4];
// now lets merge them
const mergedArray = firstArray.concat(secondArray); // [1,2,2,3,4]
const removeDuplicates = new Set(mergedArray);
on dirait que la réponse acceptée est la plus lente de mes tests;
remarque, je suis de la fusion de 2 tableaux d'objets par Clé
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<button type='button' onclick='doit()'>do it</button>
<script>
function doit(){
var items = [];
var items2 = [];
var itemskeys = {};
for(var i = 0; i < 10000; i++){
items.push({K:i, C:"123"});
itemskeys[i] = i;
}
for(var i = 9000; i < 11000; i++){
items2.push({K:i, C:"123"});
}
console.time('merge');
var res = items.slice(0);
//method1();
method0();
//method2();
console.log(res.length);
console.timeEnd('merge');
function method0(){
for(var i = 0; i < items2.length; i++){
var isok = 1;
var k = items2[i].K;
if(itemskeys[k] == null){
itemskeys[i] = res.length;
res.push(items2[i]);
}
}
}
function method1(){
for(var i = 0; i < items2.length; i++){
var isok = 1;
var k = items2[i].K;
for(var j = 0; j < items.length; j++){
if(items[j].K == k){
isok = 0;
break;
}
}
if(isok) res.push(items2[i]);
}
}
function method2(){
res = res.concat(items2);
for(var i = 0; i < res.length; ++i) {
for(var j = i+1; j < res.length; ++j) {
if(res[i].K === res[j].K)
res.splice(j--, 1);
}
}
}
}
</script>
</body>
</html>
pour le plaisir... voici une solution en une seule ligne:
const x = [...new Set([['C', 'B'],['B', 'A']].reduce( (a, e) => a.concat(e), []))].sort()
// ['A', 'B', 'C']
Pas particulièrement lisible, mais il peut aider quelqu'un:
- applique une fonction de réduction avec la valeur initiale de l'accumulateur réglée sur un tableau vide.
- la fonction reduce utilise concat pour ajouter chaque sous-réseau au réseau d'accumulateurs.
- le résultat de ceci est passé comme un paramètre de constructeur pour créer un nouveau
Set
. - l'opérateur spread est utilisé pour convertir le
Set
en tableau. - la fonction
sort()
est appliquée au nouveau tableau.
DeDuplicate single ou Merge et DeDuplicate multiple array inputs. L'exemple ci-dessous.
a ES6, pour de la, de la déstructuration
j'ai écrit cette fonction simple qui prend plusieurs arguments de tableau. Fait à peu près la même chose que la solution ci-dessus il suffit d'avoir cas d'utilisation plus pratique. Cette fonction ne concaténate pas les valeurs dupliquées dans un tableau seulement de sorte qu'elle puisse les supprimer à un stade ultérieur.
SHORT Définition de la fonction (seulement 9 lignes )
/**
* 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);
}
UTILISER L'EXEMPLE 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]
fusionner deux tableaux et supprimer les doublons dans es6
let arr1 = [3, 5, 2, 2, 5, 5];
let arr2 = [2, 1, 66, 5];
let unique = [...new Set([...arr1,...arr2])];
console.log(unique);
// [ 3, 5, 2, 1, 66 ]