2015-10-21 46 views
3

是否有一个JavaScript相当于Clojure的“减少”功能或Python的itertools.accumulate?换句话说,给定的阵列[x_0, x_1, x_2 ... x_n-1]和一个函数f(prev, next),它将返回长度n的阵列与值:JavaScript相当于Clojure的“减少”或Python的itertools.accumulate

[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 ] 

但我想知道是否有办法写somet更简单就像

[1, 1, 1, 1].reductions(function(prev, next) {return prev + next;}); 

如果不是,有没有比我写的更习惯的方式来做到这一点在JavaScript?

+0

如果你不'不介意的图书馆,看看[Underscore](http://underscorejs.org/)它有一个reduce函数,它应该完成你想要做的事情 – jcern

+0

@jcern:这不是一个简单的减少(和普通的JS现在'减少',除非你有t o支持unmentionables)。 – Amadan

+0

再次与图书馆,[拉姆达](http://ramdajs.com)(披露:我是作者)有['扫描'](http://ramdajs.com/docs/#scan)和[' mapAccum'](http://ramdajs.com/docs/#mapAccum),它以这种方式工作。 –

回答

3
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] 

我会亲自使用第一个。

编辑:

有没有这样做,不需要我有一个随机的全局变量,你的第一个建议的方法(C在这种情况下)左右浮动?如果我忘记将c重新初始化为0,那么我第二次写a.map(...)就会给出错误的答案。

当然 - 你可以封装它。

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 
+0

有没有办法做你的第一个建议,并不要求我有一个随机的全局变量(本例中为c)浮动?如果我忘记将c重新初始化为0,那么我第二次写a.map(...)就会给出错误的答案。 – OracleOfNJ

+0

谢谢,接受答案B/C封装版本。 – OracleOfNJ

0

留给后人,如果你在你使用到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; 
} 

此外,其他高阶函数可以用在减少,例如术语“地图”,如下图所示:

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; 
} 
0

我写了一个无状态的版本

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)))) 
}