Есть ли способ map
/ reduce
/ filter
/ etc a Set
в JavaScript или мне придется написать свой собственный?
Вот несколько разумных 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;
};
Возьмем небольшой набор
let s = new Set([1,2,3,4]);
И немного глупых функций
const times10 = x => x * 10;
const add = (x,y) => x + y;
const even = x => x % 2 === 0;
И посмотрите, как они работают
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
Разве это не хорошо? Да, я тоже так думаю. Сравните это с уродливым использованием итератора
// puke
let newSet = new Set();
for (let v in s) {
newSet.add(times10(v));
}
И
// barf
let sum = 0;
for (let v in s) {
sum = sum + v;
}
Есть ли лучший способ выполнить map
и reduce
использовать Set
в JavaScript?
javascript
set
ecmascript-6
reduce
Спасибо
источник
источник
Set
том, что наборы не являются функторами.var s = new Set([1,2,3,4]); s.map((a) => 42);
. Он изменяет количество элементов, чегоmap
обычно не должно быть. Еще хуже, если вы сравниваете только части сохраненных объектов, потому что тогда технически не указано, какой из них вы получите.forEach
существует для этого сценария, но почемуreduce
тогда нет ?Ответы:
Краткий способ сделать это - преобразовать его в массив с помощью оператора распространения ES6.
Тогда вам будут доступны все функции массива.
источник
Array.from
том, чтоArray.from
работает с TypeScript. Использование[...mySet]
дает ошибку:TS2461: Type 'Set<number>' is not an array type.
@@iterator
метод.ERROR TypeError: this.sausages.slice is not a function
Подводя итог дискуссии с комментариями: в то время как нет никаких технических причин для набора в не имеют
reduce
, это в настоящее время не предусмотрено , и мы можем только надеяться , что изменения в ES7.Что касается
map
одного вызова, это может нарушитьSet
ограничение, поэтому его присутствие здесь может быть спорным.Рассмотрите возможность сопоставления с функцией
(a) => 42
- она изменит размер набора на 1, и это может быть , а может и не быть тем, что вы хотели.Если вы согласны с нарушением этого правила, потому что, например, вы все равно собираетесь свернуть, вы можете применить
map
часть к каждому элементу непосредственно перед их передачейreduce
, тем самым принимая, что промежуточная коллекция ( которая на данный момент не является Set ), которая будут сокращены, возможно, дублированные элементы. По сути, это эквивалентно преобразованию в массив для обработки.источник
s.map(a => 42)
приведет кSet { 42 }
таким отображенный результат будет разной длины , но не будет «дублируются» элементы. Возможно, обновите формулировку, и я приму этот ответ.Причина отсутствия коллекций
map
/reduce
/filter
onMap
/,Set
кажется, в основном концептуальные проблемы. Если каждый тип коллекции в Javascript действительно указывает свои собственные итерационные методы только для того, чтобывместо того
Альтернативой было указать map / reduce / filter как часть протокола итерации / итератора, поскольку
entries
/values
/keys
returnIterator
s. Вполне возможно, однако, что не все итерации также могут быть «отображены». Другой альтернативой было определение отдельного «протокола сбора» именно для этой цели.Однако я не знаю, как сейчас обсуждают эту тему на ES.
источник