Javascript 相当于 Clojure 的 "reductions" 或 python 的 itertools.accumulate
Javascript equivalent to Clojure's "reductions" or python's itertools.accumulate
有没有等同于 Clojure 的 "reductions" 函数或 Python 的 itertools.accumulate
的 JavaScript?换句话说,给定一个数组 [x_0, x_1, x_2 ... x_n-1]
和一个函数 f(prev, next)
,它将 return 一个长度为 n
的数组,其值为:
[x_0, f(x_0, x_1), f(f(x_0, x_1), x_2)... f(f(f(...)), x_n)]
我正在模拟以下所需的行为:
function accumsum(prev, next) {
last = prev[prev.length - 1] || 0;
prev.push(last + next);
return prev;
}
var x = [1, 1, 1, 1];
var y = x.reduce(accumsum, []);
var z = y.reduce(accumsum, []);
console.log(x);
console.log(y);
console.log(z);
其中显示:
[ 1, 1, 1, 1 ]
[ 1, 2, 3, 4 ]
[ 1, 3, 6, 10 ]
但我想知道是否有一种方法可以写一些更简单的东西,比如
[1, 1, 1, 1].reductions(function(prev, next) {return prev + next;});
如果没有,JavaScript 中是否有比我写的更惯用的方法?
var a = [1, 1, 1, 1];
var c = 0;
a.map(function(x) { return c += x; })
// => [1, 2, 3, 4]
a.reduce(function(c, a) {
c.push(c[c.length - 1] + a);
return c;
}, [0]).slice(1);
// => [1, 2, 3, 4]
我个人会使用第一个。
编辑:
Is there a way of doing your first suggestion that doesn't require me to have a random global variable (c in this case) floating around? If I forgot to re-initialize c back to 0, the second time I wrote a.map(...) it would give the wrong answer.
当然 - 你可以封装它。
function cumulativeReduce(fn, start, array) {
var c = start;
return array.map(function(x) {
return (c = fn(c, x));
});
}
cumulativeReduce(function(c, a) { return c + a; }, 0, [1, 1, 1, 1]);
// => [1, 2, 3, 4]
c
// => ReferenceError - no dangling global variables
为了后代,如果您使用的是旧版本 JavaScript,或者无法访问 Underscore。
从头开始实施并不难,具有一定的教育价值。
这是一种方法:
function reduce(a, fn, memo) {
var i;
for (i = 0; i < a.length; ++i) {
if ( typeof memo === 'undefined' && i === 0 ) memo = a[i];
else memo = fn(memo, a[i]);
}
return memo;
}
此外,其他高阶函数也可以用reduce来写,例如"map",此处显示:
function map(a, fn) {
return reduce(a, function(memo, x) {
return memo.concat(fn(a));
}, []);
}
作为参考,等效的命令式(和更快的)地图版本为:
function map2(a, fn) {
var newA = [], i;
for (i = 0; i < a.length; ++i) {
newA.push(fn(a[i]));
}
return newA;
}
我写了一个无状态版本
function reductions(coll, reducer, init) {
if (!coll.length) {
return [init]
}
if (init === undefined) {
return reductions(_.drop(coll, 1), reducer, _.first(coll))
}
return [init].concat(reductions(_.drop(coll, 1), reducer, reducer(init, _.first(coll))))
}
有没有等同于 Clojure 的 "reductions" 函数或 Python 的 itertools.accumulate
的 JavaScript?换句话说,给定一个数组 [x_0, x_1, x_2 ... x_n-1]
和一个函数 f(prev, next)
,它将 return 一个长度为 n
的数组,其值为:
[x_0, f(x_0, x_1), f(f(x_0, x_1), x_2)... f(f(f(...)), x_n)]
我正在模拟以下所需的行为:
function accumsum(prev, next) {
last = prev[prev.length - 1] || 0;
prev.push(last + next);
return prev;
}
var x = [1, 1, 1, 1];
var y = x.reduce(accumsum, []);
var z = y.reduce(accumsum, []);
console.log(x);
console.log(y);
console.log(z);
其中显示:
[ 1, 1, 1, 1 ]
[ 1, 2, 3, 4 ]
[ 1, 3, 6, 10 ]
但我想知道是否有一种方法可以写一些更简单的东西,比如
[1, 1, 1, 1].reductions(function(prev, next) {return prev + next;});
如果没有,JavaScript 中是否有比我写的更惯用的方法?
var a = [1, 1, 1, 1];
var c = 0;
a.map(function(x) { return c += x; })
// => [1, 2, 3, 4]
a.reduce(function(c, a) {
c.push(c[c.length - 1] + a);
return c;
}, [0]).slice(1);
// => [1, 2, 3, 4]
我个人会使用第一个。
编辑:
Is there a way of doing your first suggestion that doesn't require me to have a random global variable (c in this case) floating around? If I forgot to re-initialize c back to 0, the second time I wrote a.map(...) it would give the wrong answer.
当然 - 你可以封装它。
function cumulativeReduce(fn, start, array) {
var c = start;
return array.map(function(x) {
return (c = fn(c, x));
});
}
cumulativeReduce(function(c, a) { return c + a; }, 0, [1, 1, 1, 1]);
// => [1, 2, 3, 4]
c
// => ReferenceError - no dangling global variables
为了后代,如果您使用的是旧版本 JavaScript,或者无法访问 Underscore。
从头开始实施并不难,具有一定的教育价值。
这是一种方法:
function reduce(a, fn, memo) {
var i;
for (i = 0; i < a.length; ++i) {
if ( typeof memo === 'undefined' && i === 0 ) memo = a[i];
else memo = fn(memo, a[i]);
}
return memo;
}
此外,其他高阶函数也可以用reduce来写,例如"map",此处显示:
function map(a, fn) {
return reduce(a, function(memo, x) {
return memo.concat(fn(a));
}, []);
}
作为参考,等效的命令式(和更快的)地图版本为:
function map2(a, fn) {
var newA = [], i;
for (i = 0; i < a.length; ++i) {
newA.push(fn(a[i]));
}
return newA;
}
我写了一个无状态版本
function reductions(coll, reducer, init) {
if (!coll.length) {
return [init]
}
if (init === undefined) {
return reductions(_.drop(coll, 1), reducer, _.first(coll))
}
return [init].concat(reductions(_.drop(coll, 1), reducer, reducer(init, _.first(coll))))
}