Czy istnieje sposób na map
/ reduce
/ filter
/ etc a Set
w JavaScript, czy będę musiał napisać własny?
Oto kilka rozsądnych Set.prototype
rozszerzeń
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;
};
Weźmy mały zestaw
let s = new Set([1,2,3,4]);
I kilka głupich małych funkcji
const times10 = x => x * 10;
const add = (x,y) => x + y;
const even = x => x % 2 === 0;
I zobacz, jak działają
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
Czy to nie miłe? Tak, też tak myślę. Porównaj to z brzydkim użyciem iteratora
// puke
let newSet = new Set();
for (let v in s) {
newSet.add(times10(v));
}
I
// barf
let sum = 0;
for (let v in s) {
sum = sum + v;
}
Czy jest lepszy sposób na wykonanie map
i reduce
użycie Set
w JavaScript?
javascript
set
ecmascript-6
reduce
Dziękuję Ci
źródło
źródło
Set
polega na tym, że zestawy nie są funktorami.var s = new Set([1,2,3,4]); s.map((a) => 42);
. Zmienia liczbę elementów, comap
zwykle nie powinno. Jeszcze gorzej, jeśli porównujesz tylko części zachowanych obiektów, ponieważ wtedy technicznie nie jest określone, który z nich otrzymasz.forEach
istnieje dla tego scenariusza, ale dlaczego niereduce
?Odpowiedzi:
Krótkim sposobem na to jest przekonwertowanie go na tablicę za pośrednictwem operatora rozproszenia ES6.
Wtedy wszystkie funkcje macierzy są dostępne.
źródło
Array.from
żeArray.from
działa z TypeScript. Użycie[...mySet]
daje błąd:TS2461: Type 'Set<number>' is not an array type.
@@iterator
metody.ERROR TypeError: this.sausages.slice is not a function
Podsumowując dyskusję na podstawie komentarzy: chociaż nie ma technicznych powodów, aby nie mieć zestawu
reduce
, obecnie nie jest dostarczany i możemy mieć tylko nadzieję, że zmieni się w ES7.Jeśli chodzi o
map
wywołanie tego samego, mogłoby to naruszyćSet
ograniczenie, więc jego obecność tutaj może być dyskusyjna.Rozważ mapowanie za pomocą funkcji
(a) => 42
- zmieni to rozmiar zestawu na 1 i może to być lub nie to, czego chciałeś.Jeśli nie masz nic przeciwko naruszaniu tego, ponieważ np. I tak zamierzasz spasować, możesz zastosować
map
część na każdym elemencie tuż przed przekazaniem goreduce
, akceptując w ten sposób, że kolekcja pośrednia ( która w tym momencie nie jest zestawem ) jest zostaną zredukowane, mogą mieć zduplikowane elementy. Jest to zasadniczo równoważne z konwersją do Array w celu przetwarzania.źródło
s.map(a => 42)
spowodujeSet { 42 }
, że zmapowany wynik będzie miał inną długość, ale nie będzie "zduplikowanych" elementów. Może zaktualizuj sformułowanie, a zaakceptuję tę odpowiedź.Wydaje się, że przyczyną braku
map
/reduce
/filter
naMap
/Set
kolekcji są głównie problemy koncepcyjne. Czy każdy typ kolekcji w Javascript rzeczywiście określa swoje własne iteracyjne metody, aby to umożliwićzamiast
Alternatywą było określenie map / redukuj / filtruj jako części iterowalnego / iteracyjnego protokołu, ponieważ
entries
/values
/keys
returnIterator
s. Można sobie jednak wyobrazić, że nie każdy element iterowalny jest również „mapowalny”. Inną alternatywą było określenie w tym celu odrębnego „protokołu zbiórki”.Nie znam jednak aktualnej dyskusji na ten temat w ES.
źródło