可以在Javascript中使用reduce编写bigram(或ngram)函数吗?

时间:2015-01-19 21:20:49

标签: javascript functional-programming reduce n-gram

我知道Javascript中的.reduce函数有一个previouscurrent变量“内置”的概念,可以说,在其定义中。所以我很好奇为什么这不起作用:

var bigrams = [0, 1, 2, 3, 4].reduce(function(previous, current) {
  return [previous, current]
});

我认为这并不意味着我的意思,因为现在bigrams包含:

[[[[0,1],2],3],4]

当我想要的是:

[[0,1],[1,2],[2,3],[3,4]]

我认为这与结果应该被推入累加器这一事实有关(这应该是一个空数组,如:arr.reduce(/*magic*/, [])

  • 我不应该使用.reduce来执行此操作吗?
  • 如果是这样,还有另一种“功能性”方式吗?
  • 如何避免这种嵌套行为?

1 个答案:

答案 0 :(得分:4)

reduce的工作方式是将一个调用的输出用作下一个调用的输入。如果我们将您的功能命名为f,则您的通话相当于:

f(f(f(f(0, 1), 2), 3), 4)

换句话说,previous并不意味着“原始数组中的前一项”,它意味着“之前调用该函数的结果”。

reduce对于此任务来说不是一个很好的选择,因为顾名思义,它的目标是数组减少到单个值。执行此操作的一种“功能”方法是使用zip并使用其尾部(除第一个元素之外的所有元素)压缩数组,如this Haskell example中所示。但是,Javascript没有内置的zip功能。使用this answer中的第二个zip实现:

function zip() {
    var args = [].slice.call(arguments);
    var shortest = args.length==0 ? [] : args.reduce(function(a,b){
        return a.length<b.length ? a : b
    });

    return shortest.map(function(_,i){
        return args.map(function(array){return array[i]})
    });
}

你可以这样做:

var x = [0, 1, 2, 3, 4]
zip(x, x.slice(1))

但是,在JavaScript中,我认为大多数人可能会迭代地执行此操作,例如this question的答案。