:::: MENU ::::

L’union de tableaux en Javascript

Il arrivera forcément un jour ou vous aurez à effectuer l’union de deux ou plusieurs tableaux. Union qui doit prendre en compte et éviter la possibilité d’éléments dupliqués. Hélas javascript ne propose pas nativement cette possibilité.

Même si cette opération est assez simple, il existe plusieurs méthodes pour y arriver facilement, l’occasion d’utiliser l’approche fonctionnelle d’ Ecmascript 5 mais surtout d’avoir un aperçu des nouvelles fonctionnalités offertes par Ecmascript 6.

A l’ancienne, fonctionnel mon ami

Prenons deux tableaux a et b que l’on veut unir :


var a = [1,2,3,4];

var b = [3,4,5];

En fait, il s’agit d’une concaténation et d’un filtrage. A l’aide du chaînage permis par les traitements sur les tableaux, cette opération est relativement simple.


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

var c = union(a,b); //1,2,3,4,5

Les fonctions flèches d’ES6 permettent aussi de réduire la syntaxe de notre fonction utilitaire.


const union = (a, b) => a.concat(b.filter((el) => a.indexOf(el) === -1));

Un peu de nouveauté : Spread, Set et iterators

En jouant avec les nouvelles fonctionnalités d’ EcmaScript 6, on peut obtenir le même résultat:

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

Explications :

Un tableau est un itérable qui peut être décomposé par l’opérateur spread . En bref, il extrait les données du tableau.

En créant un nouveau tableau à partir de nos deux variables décomposées, on réalise finalement une concaténation de tableaux

Pour effectuer la dé-duplication on se sert du nouveau type d’objet Set qui n’accepte que des valeurs uniques et qu’on initialise à partir du tableau précédemment créé.

Enfin, comme Set est aussi un itérable on le décompose pour en extraire ses données et les intégrer à un nouveau tableau. C’est aussi une méthode pour convertir un itérable en tableau.

Couche de finition : Rest parameters

L’avantage de ce processus et qu’il permet de travailler sur plusieurs tableaux facilement. Contrairement à la solution en Ecmascript 5 qui deviendrait un peu plus verbeuse, on peut utiliser ici les rest parameters .


const union = ...args => [...new Set(args.reduce((a,b) => a.concat(b)))];

var c = union(a,b,a,a,b); //1,2,3,4,5

Ou encore avec une petite fonction utilitaire :


const flat = arr => arr.reduce((a,b) => a.concat(b)) ;

const union = ...args => [...new Set(flat(args))];                                                 

 

Conclusion

On le constate, il y a différentes méthodes plus ou moins simples pour arriver à la même chose. Ce que l’on peut retenir c’est que l’usage de fonctions utilitaires et du chainage des traitements sur les tableaux permet d’arriver à des calculs complexes en gardant un code lisible.

C’est aussi une bonne illustration de ce qu’apportent les nouvelles fonctionnalités d’Ecmascript 6 pour ce genre de techniques.

Notes:
1. qui porte bien son nom puisque spread operator se traduit par opérateur de décomposition
2. donc en EcmaScript 6 pour concaténer des tableaux on fait  […a,…b]
3. Reste encore à comparer les performances des différentes solutions
qui porte bien son nom puisque spread operator se traduit par opérateur de décomposition
donc en EcmaScript 6 pour concaténer des tableaux on fait  […a,…b]
Reste encore à comparer les performances des différentes solutions

7 Comments

  • Répondre Guillaume Denry |

    Sinon, juste pour info, je viens d’essayer et il n’existe pas de polyfill ES5 (j’utilise babel ici) pour « spreader » un Set :-( ([…new Set([1, 2])] échoue)

    Dommage, je vais devoir attendre encore un peu :)

    • Répondre maxdow |

      Je pense que c’est peut etre un probleme de config ou il manque l’option runtime de babel par exemple.

      Ce que tu veux faire ( dans l’exemple ) c’est transformer un Set en Array. Babel transpile ça avec la fonction toConsumableArray(). Mais cette fonction utilise Array.from . Donc potentiellement il faut aussi le polyfill pour ça.

      Autre point sinon, ton navigateur cible n’implémente pas Set . La il faut polyfiller avec core-js ( require(‘core-js/fn/set’) ) . Je pense que le spread ( consumableArray ) fonctionne toujours mais ça reste à tester .

    • Répondre maxdow |

      Oui c’est vrai, en fait il y a surement un paquet d’autres façons de le faire mais le but ici est surtout de présenter des nouvelles features d’ES6 ;)

So, what do you think ?