Existe alguma maneira de map
/ reduce
/ filter
/ etc a Set
em JavaScript ou terei que escrever minha própria?
Aqui estão algumas Set.prototype
extensões sensatas
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;
};
Vamos dar um pequeno set
let s = new Set([1,2,3,4]);
E algumas pequenas funções estúpidas
const times10 = x => x * 10;
const add = (x,y) => x + y;
const even = x => x % 2 === 0;
E veja como eles funcionam
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
Isso não é legal? Sim, eu também acho. Compare isso com o feio uso do iterador
// puke
let newSet = new Set();
for (let v in s) {
newSet.add(times10(v));
}
E
// barf
let sum = 0;
for (let v in s) {
sum = sum + v;
}
Existe alguma maneira melhor de realizar map
e reduce
usar um Set
em JavaScript?
javascript
set
ecmascript-6
reduce
Obrigado
fonte
fonte
Set
é que Sets não são Functors.var s = new Set([1,2,3,4]); s.map((a) => 42);
. Ele altera o número de elementos, o quemap
normalmente não deveria ser feito. Pior ainda, se você estiver comparando apenas partes dos objetos mantidos, porque, tecnicamente, não é especificado qual deles você obterá.forEach
existe para esse cenário, mas por que nãoreduce
?Respostas:
Uma maneira abreviada de fazer isso é convertê-lo em uma matriz por meio do operador de spread ES6.
Todas as funções da matriz estão disponíveis para você.
fonte
Array.from
é queArray.from
funciona com o TypeScript. Usando[...mySet]
dá o erro:TS2461: Type 'Set<number>' is not an array type.
@@iterator
método.ERROR TypeError: this.sausages.slice is not a function
Para resumir a discussão a partir dos comentários: embora não haja motivos técnicos para o conjunto não ter
reduce
, ele não é fornecido no momento e só podemos esperar que ele mude no ES7.Quanto a
map
chamá-lo por si só, pode violar aSet
restrição; portanto, sua presença aqui pode ser discutível.Considere o mapeamento com uma função
(a) => 42
- ele mudará o tamanho do conjunto para 1, e isso pode ou não ser o que você queria.Se você concorda em violar isso, porque, por exemplo, você vai dobrar de qualquer maneira, pode aplicar a
map
parte em todos os elementos antes de passá-los parareduce
, aceitando assim que a coleção intermediária ( que não é um conjunto neste momento ) seja será reduzido pode ter elementos duplicados. Isso é essencialmente equivalente à conversão em Array para processamento.fonte
s.map(a => 42)
resultará emSet { 42 }
um resultado diferente, mas não haverá elementos "duplicados". Talvez atualize o texto e eu aceito esta resposta.A causa da falta de
map
/reduce
/filter
onMap
/Set
coleções parece ser principalmente preocupações conceituais. Cada tipo de coleção em Javascript deve realmente especificar seus próprios métodos iterativos apenas para permitir issoao invés de
Uma alternativa era especificar mapear / reduzir / filtrar como parte do protocolo iterável / iterador, já que
entries
/values
/keys
returnIterator
s. É concebível, porém, que nem todo iterável também seja "mapeável". Outra alternativa era especificar um "protocolo de coleta" separado para esse objetivo.No entanto, não conheço a discussão atual sobre este tópico no ES.
fonte