为了形式化已经指出的内容,reducer 是一种 catamorphism,它接受两个可能是相同类型的参数,并返回与第一个参数匹配的类型。
function reducer (accumulator: X, currentValue: Y): X { }
这意味着 reducer 的主体需要将currentValue
的当前值转换accumulator
为 new 的值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 不匹配的单个值,reduce 是您可能会考虑的事情。
事实上,map 和 filter 都可以实现为reductions:
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);