Aby sformalizować to, co zostało wskazane, reduktor jest katamorfizmem, który przyjmuje dwa argumenty, które mogą być tego samego typu przez przypadek, i zwraca typ, który pasuje do pierwszego argumentu.
function reducer (accumulator: X, currentValue: Y): X { }
Oznacza to, że korpus reduktora musi polegać na konwersji currentValue
i bieżącej wartości accumulator
na wartość nowego accumulator
.
Działa to w prosty sposób podczas dodawania, ponieważ zarówno akumulator, jak i wartości elementu są tego samego typu (ale służą innym celom).
[1, 2, 3].reduce((x, y) => x + y);
To po prostu działa, ponieważ wszystkie są liczbami.
[{ age: 5 }, { age: 2 }, { age: 8 }]
.reduce((total, thing) => total + thing.age, 0);
Teraz podajemy wartość początkową agregatorowi. Wartością początkową powinien być typ, jakiego oczekuje się od agregatora (typ, który ma się pojawić jako wartość końcowa), w zdecydowanej większości przypadków. Chociaż nie musisz tego robić (i nie powinno tak być), należy o tym pamiętać.
Kiedy już to wiesz, możesz napisać znaczące redukcje dla innych problemów w relacji n: 1.
Usuwanie powtarzających się słów:
const skipIfAlreadyFound = (words, word) => words.includes(word)
? words
: words.concat(word);
const deduplicatedWords = aBunchOfWords.reduce(skipIfAlreadyFound, []);
Podając liczbę wszystkich znalezionych słów:
const incrementWordCount = (counts, word) => {
counts[word] = (counts[word] || 0) + 1;
return counts;
};
const wordCounts = words.reduce(incrementWordCount, { });
Zmniejszenie tablicy tablic do pojedynczej płaskiej tablicy:
const concat = (a, b) => a.concat(b);
const numbers = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
].reduce(concat, []);
Za każdym razem, gdy chcesz przejść od szeregu rzeczy do pojedynczej wartości, która nie pasuje do 1: 1, warto rozważyć redukcję.
W rzeczywistości mapę i filtr można wdrożyć jako redukcje:
const map = (transform, array) =>
array.reduce((list, el) => list.concat(transform(el)), []);
const filter = (predicate, array) => array.reduce(
(list, el) => predicate(el) ? list.concat(el) : list,
[]
);
Mam nadzieję, że zapewnia to dodatkowy kontekst użycia reduce
.
Jedynym dodatkiem do tego, do czego jeszcze się nie włamałem, jest oczekiwanie, że typy wejściowe i wyjściowe mają być dynamiczne, ponieważ elementy tablicy są funkcjami:
const compose = (...fns) => x =>
fns.reduceRight((x, f) => f(x), x);
const hgfx = h(g(f(x)));
const hgf = compose(h, g, f);
const hgfy = hgf(y);
const hgfz = hgf(z);
arr.reduce(function(a,b){return a + b})
drugi przykład.