# How to map/reduce/filter a Set in JavaScript?

Is there any way to `map`/`reduce`/`filter`/etc a `Set` in JavaScript or will I have to write my own?

Here's some sensible `Set.prototype` extensions

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

Let's take a little set

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

And some stupid little functions

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

And see how they work

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

Isn't that nice ? Yeah, I think so too. Compare that to the ugly iterator usage

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

And

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

Is there any better way to accomplish `map` and `reduce` using a `Set` in JavaScript? A short-hand way to do it is to convert it to an array via the ES6 spread operator.

Then all the array functions are available to you.

``````const mySet = new Set([1,2,3,4]);
[...mySet].reduce()
`````` To sum up the discussion from comments: while there are no technical reasons for set to not have `reduce`, it's not currently provided and we can only hope it changes in ES7.

As for `map`, calling it alone could violate the `Set` constraint, so its presence here might be debatable.

Consider mapping with a function `(a) => 42` - it will change the set's size to 1, and this might or might not be what you wanted.

If you're ok with violating that because e.g. you're going to fold anyway, you can apply the `map` part on every element just before passing them to `reduce`, thus accepting that the intermediate collection (which isn't a Set at this point) that's going to be reduced might have duplicated elements. This is essentially equivalent to converting to Array to do processing. The cause of the lack of `map`/`reduce`/`filter` on `Map`/`Set` collections seem to be mainly conceptual concerns. Should each collection type in Javascript actually specify its own iterative methods only to allow this

``````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]);
``````

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

An alternative were to specify map/reduce/filter as part of the iterable/iterator protocol, since `entries`/`values`/`keys` return `Iterator`s. It is conceivable though that not every iterable is also "mappable". Another alternative were to specify a separate "collection protocol" for this very purpose.

However, I do not know the current discussion on this topic at ES.