web-dev-qa-db-fra.com

Comment mapper / réduire / filtrer un ensemble en JavaScript?

Existe-t-il un moyen de map/reduce/filter/etc a Set en JavaScript ou devrai-je écrire le mien?

Voici quelques extensions sensibles Set.prototype

Set.prototype.map = function map(f) {
  var newSet = new Set();
  for (var v of this.values()) newSet.add(f(v));
  return newSet;
};

Set.prototype.reduce = function(f,initial) {
  var result = initial;
  for (var v of this) result = f(result, v);
  return result;
};

Set.prototype.filter = function filter(f) {
  var newSet = new Set();
  for (var v of this) if(f(v)) newSet.add(v);
  return newSet;
};

Set.prototype.every = function every(f) {
  for (var v of this) if (!f(v)) return false;
  return true;
};

Set.prototype.some = function some(f) {
  for (var v of this) if (f(v)) return true;
  return false;
};

Prenons un petit set

let s = new Set([1,2,3,4]);

Et quelques petites fonctions stupides

const times10 = x => x * 10;
const add = (x,y) => x + y;
const even = x => x % 2 === 0;

Et voir comment ils fonctionnent

s.map(times10);    //=> Set {10,20,30,40}
s.reduce(add, 0);  //=> 10
s.filter(even);    //=> Set {2,4}
s.every(even);     //=> false
s.some(even);      //=> true

N'est-ce pas gentil? Oui, je le pense aussi. Comparez cela à l'utilisation laide d'itérateur

// puke
let newSet = new Set();
for (let v in s) {
  newSet.add(times10(v));
}

Et

// barf
let sum = 0;
for (let v in s) {
  sum = sum + v;
}

Existe-t-il un meilleur moyen d'accomplir map et reduce à l'aide de Set en JavaScript?

87
user633183

Un moyen rapide de le faire est de le convertir en tableau via l'opérateur de propagation ES6.

Toutes les fonctions du tableau sont alors disponibles.

const mySet = new Set([1,2,3,4]);
[...mySet].reduce()
69
ZephDavies

Pour résumer la discussion à partir de commentaires: bien qu’il n’y ait aucune raison technique de définir pas avoir reduce, il n’est pas fourni pour le moment et nous ne peut qu’espérer que cela change dans ES7.

Quant à map, l'appeler seul pourrait violer la contrainte Set, de sorte que sa présence ici pourrait être discutable.

Pensez à mapper avec une fonction (a) => 42 _ - la taille de l'ensemble sera changée à 1, et cela pourrait ou non être ce que vous vouliez.

Si vous acceptez de violer cela parce que, par exemple, vous allez quand même plier, vous pouvez appliquer la partie map à chaque élément juste avant de les passer à reduce, acceptant ainsi que la collection intermédiaire (qui n'est pas une Défini à ce stade) qui va être réduit peut avoir des éléments en double. Ceci est essentiellement équivalent à la conversion en tableau pour effectuer le traitement.

20
Bartek Banachewicz

La cause du manque de collections map/reduce/filter sur Map/Set semble être principalement de nature conceptuelle. Chaque type de collection en Javascript doit-il spécifier ses propres méthodes itératives uniquement pour permettre cette

const mySet = new Set([1,2,3]);
const myMap = new Map([[1,1],[2,2],[3,3]]);

mySet.map(x => x + 1);
myMap.map(([k, x]) => [k, x + 1]);

au lieu de

new Set(Array.from(mySet.values(), x => x + 1));
new Map(Array.from(myMap.entries(), ([k, x]) => [k, x + 1]));

Une alternative consistait à spécifier map/reduction/filter dans le cadre du protocole iterable/iterator, puisque entries/values/keys return Iterators. Il est toutefois concevable que tous les éléments itératifs ne soient pas "mappables". Une autre alternative consistait à spécifier un "protocole de collecte" distinct à cette fin.

Cependant, je ne connais pas la discussion en cours sur ce sujet à ES.

7
user6445533