【发布时间】:2014-12-02 15:11:41
【问题描述】:
对于数组a 的元素上的关联操作f,以下关系应成立:a.reduce(f) 应等效于a.reduceRight(f)。
确实,它确实适用于同时具有关联性和交换性的操作。为了 示例:
const a = [0,1,2,3,4,5,6,7,8,9];
const add = (a, b) => a + b;
console.log(a.reduce(add));
console.log(a.reduceRight(add));
但它不适用于关联但不可交换的操作。例如:
const a = [[0,1],[2,3],[4,5],[6,7],[8,9]];
const concat = (a, b) => a.concat(b);
console.log(JSON.stringify(a.reduce(concat)));
console.log(JSON.stringify(a.reduceRight(concat)));
我们需要将f 的参数翻转为reduceRight 以使它们等效:
const a = [[0,1],[2,3],[4,5],[6,7],[8,9]];
const concat = (a, b) => a.concat(b);
const concatRight = (b, a) => a.concat(b);
console.log(JSON.stringify(a.reduce(concat)));
console.log(JSON.stringify(a.reduceRight(concatRight)));
这让我相信reduceRight的原生实现是错误的。
我认为reduceRight函数应该实现如下:
var REDUCE_ERROR = "Reduce of empty array with no initial value";
Array.prototype.reduceRight = function (f, acc) {
let { length } = this;
const noAcc = arguments.length < 2;
if (noAcc && length === 0) throw new TypeError(REDUCE_ERROR);
let result = noAcc ? this[--length] : acc;
while (length > 0) result = f(this[--length], result, length, this);
return result;
};
由于result 代表前一个值(右侧值),因此将其作为函数f 的第二个参数是有意义的。当前值表示左侧值。因此,将当前值作为函数f 的第一个参数是有意义的。这样,即使对于非交换关联运算,上述关系也成立。
所以,我的问题是:
-
reduceRight按照我的方式实现不是更有意义吗? - 为什么原生
reduceRight没有按照我的方式实现?
【问题讨论】:
-
这不只是因为
foldrandfoldl的操作方向不同吗?这就是两者兼而有之的意义,非交换操作必然会返回不同的结果。 -
@ssube 它们可能在不同的方向上操作,但对于关联操作它们应该返回相同的结果。例如:
foldl1 (++) xs == foldr1 (++) xs在 Haskell 中是True。
标签: javascript reduce fold associativity commutativity