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?
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()
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.
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 Iterator
s. 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.