Чтобы формализовать то, что было указано, редуктор представляет собой катаморфизм, который принимает два аргумента, которые могут совпадать с одним типом, и возвращает тип, который соответствует первому аргументу.
function reducer (accumulator: X, currentValue: Y): X { }
Это означает, что тело редуктора должно быть преобразовано, currentValue
а текущее значение в accumulator
значение нового accumulator
.
При добавлении это работает прямым образом, поскольку значения аккумулятора и элемента оказываются одного типа (но служат разным целям).
[1, 2, 3].reduce((x, y) => x + y);
Это просто работает, потому что они все числа.
[{ age: 5 }, { age: 2 }, { age: 8 }]
.reduce((total, thing) => total + thing.age, 0);
Теперь мы даем начальное значение агрегатору. Начальным значением должен быть тип, который, как вы ожидаете, будет агрегатором (тип, который вы ожидаете получить в качестве конечного значения), в подавляющем большинстве случаев. Хотя вы не обязаны это делать (и не должны этого делать), важно помнить.
Узнав об этом, вы можете написать значимые сокращения для других проблем отношений n: 1.
Удаление повторяющихся слов:
const skipIfAlreadyFound = (words, word) => words.includes(word)
? words
: words.concat(word);
const deduplicatedWords = aBunchOfWords.reduce(skipIfAlreadyFound, []);
Предоставление подсчета всех найденных слов:
const incrementWordCount = (counts, word) => {
counts[word] = (counts[word] || 0) + 1;
return counts;
};
const wordCounts = words.reduce(incrementWordCount, { });
Сокращение массива массивов до единого плоского массива:
const concat = (a, b) => a.concat(b);
const numbers = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
].reduce(concat, []);
Каждый раз, когда вы хотите перейти от множества вещей к одному значению, которое не соответствует 1: 1, уменьшение - это то, что вы могли бы рассмотреть.
Фактически, карта и фильтр могут быть реализованы как сокращения:
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,
[]
);
Я надеюсь, что это дает некоторый дополнительный контекст для использования reduce
.
Единственное дополнение к этому, которое я еще не взломал, - это когда ожидается, что типы ввода и вывода определенно должны быть динамическими, потому что элементы массива являются функциями:
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})
в виду во втором примере.