【问题标题】:Javascript equivalent to Clojure's "reductions" or python's itertools.accumulateJavascript 相当于 Clojure 的“减少”或 python 的 itertools.accumulate
【发布时间】:2016-01-19 21:01:01
【问题描述】:

是否有与 Clojure 的“reductions”函数或 Python 的 itertools.accumulate 等效的 JavaScript?换句话说,给定一个数组[x_0, x_1, x_2 ... x_n-1] 和一个函数f(prev, next),它将返回一个长度为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 中是否有比我写的更惯用的方法?

【问题讨论】:

  • 如果您不介意库,请查看 Underscore 它有一个 reduce 函数,应该可以完成您想做的事情
  • @jcern:这不是一个简单的 reduce(普通 JS 现在有 reduce,除非你必须支持不可提及的东西)。
  • 再次使用库,Ramda(披露:我是作者)有 scanmapAccum,它们以这种方式工作。
  • 感谢 Scott,我在 Clojure 上玩了几个星期,最终从功能性的 Kool-Aid 中喝了一大口。

标签: javascript python clojure functional-programming reduce


【解决方案1】:
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

【讨论】:

  • 有没有办法做你的第一个建议,不需要我有一个随机的全局变量(在这种情况下是 c)浮动?如果我忘记将 c 重新初始化为 0,那么我第二次写 a.map(...) 时会给出错误的答案。
  • 谢谢,接受答案 b/c 封装版本。
【解决方案2】:

对于后代,如果您使用的是旧版 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 来编写,例如“地图”,此处显示:

function map(a, fn) {
  return reduce(a, function(memo, x) {
    return memo.concat(fn(a));
  }, []);
}

作为参考,等效的命令(和更快)版本的 map 将是:

function map2(a, fn) {
  var newA = [], i;
  for (i = 0; i < a.length; ++i) {
    newA.push(fn(a[i]));
  }
  return newA;
}

【讨论】:

    【解决方案3】:

    我写了一个无状态的版本

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

    【讨论】:

      猜你喜欢
      • 2021-04-05
      • 1970-01-01
      • 1970-01-01
      • 2010-09-07
      • 2013-04-13
      • 1970-01-01
      • 2011-04-18
      • 2022-12-03
      • 2011-04-22
      相关资源
      最近更新 更多