1645 votes

Comment fusionner deux tableaux en JavaScript et dé-dupliquer les éléments ?

J'ai deux tableaux JavaScript :

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

Je veux que la sortie soit :

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

Les mots répétés doivent être supprimés du tableau de sortie.

Comment fusionner deux tableaux en JavaScript afin d'obtenir uniquement les éléments uniques de chaque tableau dans le même ordre qu'ils ont été insérés dans les tableaux d'origine ?

13 votes

Avant de poster une nouvelle réponse, pensez qu'il y a déjà plus de 75 réponses à cette question. Veillez à ce que votre réponse apporte des informations qui ne figurent pas parmi les réponses existantes.

0 votes

[...nouveau Set([...[1, 2, 3], ...[2, 3, 4]])] résultat [1, 2, 3, 4]

0 votes

Si vous souhaitez une solution plus générique qui couvre également la fusion profonde, jetez un coup d'œil à la page suivante. à cette question à la place. Certaines réponses couvrent également les tableaux.

1980voto

LiraNuna Points 21565

Pour simplement fusionner les tableaux (sans supprimer les doublons)

Utilisation de la version ES5 Array.concat :

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

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

Utilisation de la version ES6 déstructuration

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

Puisqu'il n'existe pas de moyen "intégré" de supprimer les doublons ( ECMA-262 a en fait Array.forEach qui serait idéal 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;
};

Ensuite, 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 permet également de conserver l'ordre des tableaux (c'est-à-dire qu'aucun tri n'est nécessaire).

Puisque de nombreuses personnes sont contrariées par l'augmentation du 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 ça :

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

331 votes

Notez que cet algorithme est O(n^2).

7 votes

Soit [a, b, c] et [x, b, d] sont les tableaux (avec des guillemets). concat donne [a, b, c, x, b, d] . La sortie de la fonction unique() ne serait-elle pas [a, c, x, b, d] . Cela ne préserve pas l'ordre je pense - je crois que l'OP veut [a, b, c, x, d]

104 votes

Le PO a accepté la première réponse qui l'a fait travailler et a signé, semble-t-il. Nous continuons à comparer les solutions des uns et des autres, à trouver et à corriger les défauts, à améliorer les performances, à nous assurer qu'elles sont compatibles partout, etc... La beauté de stackoverflow :-)

636voto

GijsjanB Points 2604

Avec Underscore.js ou Lo-Dash vous pouvez le faire :

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

0 votes

un ensemble ne préserverait pas, par définition, l'ordre d'un tableau fusionné, car il n'a pas d'ordre ?

75 votes

Ou, peut-être encore mieux que l'underscore, l'API-compatible lodash .

3 votes

@Ygg Extrait de la documentation de lodash. "Renvoie un nouveau tableau de valeurs uniques, dans l'ordre qui sont présents dans un ou plusieurs des tableaux."

354voto

simo Points 1147

Tout d'abord, concaténer les deux tableaux, puis filtrer uniquement les éléments uniques :

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]

Modifier

Comme nous l'avons suggéré, une solution plus performante consisterait à filtrer les éléments uniques dans la base de données de l'UE. b avant de le concaténer avec 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]

7 votes

La solution originale a l'avantage de supprimer les doublons dans chaque tableau source. Je suppose que cela dépend du contexte dans lequel vous vous trouvez.

0 votes

Vous pourriez fusionner différemment pour le support d'IE6 : c = Array.from(new Set(c)) ;

0 votes

Si je veux vraiment changer a à ajouter b Dans ce cas, ne serait-il pas préférable de boucler et d'utiliser la fonction "push" ? a.forEach(function(item){ if(a.indexOf(item)<0) a.push(item); });

43voto

slickplaid Points 709

Voici un point de vue légèrement différent sur la boucle. Grâce à certaines 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);
  }
}

pendant la boucle : ~589k ops/s
filtre : ~445k ops/s
lodash : 308k ops/s
pour les boucles : 225k ops/s

Un commentaire m'a fait remarquer que l'une de mes variables de configuration permettait à ma boucle de prendre de l'avance sur les autres, car elle n'avait pas à initialiser un tableau vide pour y écrire. Je suis d'accord avec cela, donc j'ai réécrit le test pour égaliser le terrain de jeu, et j'ai inclus une option encore plus rapide.

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

Dans cette solution alternative, j'ai combiné la solution du tableau associatif d'une réponse pour éliminer le problème de l'association. .indexOf() dans la boucle qui ralentissait beaucoup les choses avec une deuxième boucle, et a inclus certaines des autres optimisations que d'autres utilisateurs ont suggéré dans leurs réponses aussi.

La meilleure réponse ici, avec la double boucle sur chaque valeur (i-1), est toujours significativement plus lente. lodash est toujours aussi performant, et je le recommande toujours à tous ceux qui n'ont pas peur d'ajouter une bibliothèque à leur projet. Pour ceux qui ne veulent pas le faire, ma boucle while est toujours une bonne réponse et la réponse avec le filtre est très forte ici, battant tous mes tests avec la dernière version de Canary Chrome (44.0.2360) au moment où j'écris ces lignes.

Vérifiez La réponse de Mike et La réponse de Dan Stocker si vous voulez monter d'un cran dans la vitesse. Ce sont de loin les résultats les plus rapides après avoir passé en revue presque toutes les réponses viables.

0 votes

Il y a un défaut dans votre méthodologie : vous placez la création de array3 dans la phase d'installation, alors que ce coût devrait seulement faire partie du score de votre solution basée sur while. Avec cette 1 ligne déplacée votre solution est moins rapide que celle basée sur la boucle for. Je comprends que les tableaux peuvent être réutilisés, mais peut-être que les autres algorithmes pourraient aussi bénéficier du fait de ne pas avoir à déclarer et initialiser chaque élément de base nécessaire.

0 votes

Je suis d'accord avec votre prémisse @doldt, mais pas avec vos résultats. Il y a un défaut de conception fondamental avec la suppression des entrées basée sur la boucle, en ce sens que vous devez revérifier la longueur du tableau après avoir supprimé des éléments, ce qui entraîne un temps d'exécution plus lent. Une boucle while fonctionnant à l'envers n'a pas ces effets. Voici un exemple dans lequel je supprime autant de variables de configuration que possible sans trop modifier leur réponse originale : jsperf.com/merge-two-arrays-keeping-only-unique-values/19

0 votes

@slickplaid les tests liés sont vides, et la révision suivante à jsperf se bloque dans la boucle while.

20voto

GAgnew Points 1128
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.

4 votes

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

0 votes

Excellente solution. J'ai mis à jour le test jsperf posté ci-dessus par @slickplaid ( jsperf.com/merge-two-arrays-keeping-only-unique-values/3 ) et il semble que ce soit le plus rapide d'entre eux.

0 votes

@Cobra Au risque de paraître mesquin, sous Chrome 40.0.2214 (dernière version du 18/02/15), cette réponse est 53% plus lente que la mienne. Par contre, IE11 ne semble pas du tout optimisé pour ma réponse :) Chrome mobile est toujours aussi performant. Honnêtement, si vous utilisez lodash/_, ce qui devrait être le cas pour la plupart d'entre nous, la vraie réponse se trouve déjà assez haut dans cette liste :)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X