如何用reduce和range编写阶乘函数?

时间:2016-12-23 20:57:31

标签: javascript arrays functional-programming reduce

function range(start, end) {
  var acc = [];
  for (var i = start; i < end; i++) {
    acc.push(i);
  }
  return acc;
}

使用range函数和reduce方法,我需要重写阶乘函数。

function factorial(n) {
  // YOUR CODE HERE
}

我得到了一个提示,首先在forEach中编写函数,然后用range和reduce重写它。这是我的尝试。

function factorial(n){
  var product = 1;
  n.forEach(function(x){
    if(x===0){
      return 1;}
    product *= factorial(x-1);
  });
  return product;
}

factorial(4);

这是我的尝试。我知道这很乱,但我的问题是,当n只是一个数字而且每个数组是什么时,我如何使用forEach?因为他们希望我先使用每一个来编写阶乘函数,我需要使用基本情况吗?我还查看了MDN并尝试通过使用accumulator + currentValue来理解reduce,并想出了这个伪代码。

function factorial(n){
  n.reduce(function(x){ 
    x*range;
  });
}

factorial(5)

如果参数不是数组,我不明白如何使用reduce。

6 个答案:

答案 0 :(得分:2)

解决这个问题有两个步骤,第一步是生成一个数组以使用reduce方法,第二步实际上是使用reduce方法来找到我们的阶乘答案。

我们可以使用提供给我们的范围方法完成第一步。 range方法返回最小值(包括)和最大值(不包括)之间的所有整数值的数组。例如,如果我们致电range(1,5),则会返回[1,2,3,4]。当我们想要执行阶乘操作时,我们希望将所有先前的整数值包括乘以当前值。要获取所有先前值和当前值的数组,我们可以使用

var factors = range(1,n+1);

在我们的阶乘函数开始时。

现在我们已经拥有了所有因素,我们可以使用reduce方法将它们相乘。 reduce方法将按顺序对数组的每个值执行提供的函数。在这种情况下,我们希望将所有因素相乘。我们可以使用

var multFactors = factors.reduce(function(a,b){
    return a*b;
},1);

将数组中的每个值相乘。通过使用1作为reduce方法的第二个参数,我们确保factorial(0)不会导致任何错误(感谢@Eterm注意到这一点)

现在剩下的就是返回multFactors。

当所有这些都放在一起时,你最终得到了这个

function range(start, end) {
  var acc = [];
  for (var i = start; i < end; i++) {
    acc.push(i);
  }
  return acc;
}

function factorial(n) {
  var factors = range(1,n+1);
  var multFactors = factors.reduce(function(a,b){
    return a*b;
  },1);
  return multFactors;
}

修改

如果您想避免使用负因子进行错误,可以对n应用绝对值函数。

为此,我们可以更改

var factors = range(1,n+1);

var factors = range(1, Math.abs(n)+1);

采用负数的阶乘应该是未定义的,但是使用这个新行,我们通过使数字为正数来避免任何错误。如果要保留阶乘的符号,可以在设置multFactors之后但在返回之前添加这些行。

if(n < 0)
  multFactors *= -1;

完成后,你最终得到这个(现在有评论,因为它更长)

function range(start, end) {
  var acc = [];
  for (var i = start; i < end; i++) {
    acc.push(i);
  }
  return acc;
}

function factorial(n) {
  //Get the factors
  var factors = range(1, Math.abs(n)+1);

  //Multiply all of the factors together
  var multFactors = factors.reduce(function(a,b){
    return a*b;
  },1);

  //if n was negative make the result negative
  if(n < 0)
    multFactors *= -1;

  //return the calculated result
  return multFactors;
}

希望这有帮助。

答案 1 :(得分:0)

当你说forEach is for Arrays but n is a number时,你会发现什么。所以你需要构造你将循环的数组(后来减少)。

var n = 10;

var i = 0;

//use your "range" function to define an array from 2 to end.
var z = range(2, n + 1);

//Now we have an array we can reduce with multiplication initializing the accumulator to 1.
z.reduce(function(a,b){return a*b;}, 1);

reduce中的函数只是乘法,第二个参数初始化累加器。

此处不需要对0或1进行特殊处理,因为构造的数组将为空,而reduce将仅返回初始值1。

答案 2 :(得分:0)

您可以使用Arrayapply并为给定的起始值和结束值创建包含范围。

然后通过乘法减少。

function range(start, end) {
    return Array.apply(null, { length: end - start + 1 }).map(function (_, i) { return start + i; });
}

function multiply(a, b) { return a * b; }


var array = range(3, 7),
    product = array.reduce(multiply);

console.log(array);
console.log(product);
console.log(range(1, 10).reduce(multiply));
.as-console-wrapper { max-height: 100% !important; top: 0; }

答案 3 :(得分:0)

只需按Nothing,您可以执行以下操作;

&#13;
&#13;
Array.prototype.reduce()
&#13;
&#13;
&#13;

答案 4 :(得分:0)

这里还有很多其他答案可以提供解决问题的实用方法。我的答案是有目的的不切实际(用JavaScript编写),但旨在教你其他事情。

这个答案受到lambda演算的影响,它只有单个参数,单个表达式函数。剖析此代码将使您对高阶程序有深刻而深刻的理解。

我们首先定义Y-combinator,然后使用range实现reduceY。然后我们最终可以实现factorial

const U = f => f (f)

const Y = U (h => f => f (x => h (h) (f) (x)))

const range = Y (h => acc => x => y =>
  (x > y) ? acc : h ([...acc, x]) (x + 1) (y)
) ([]);

const reduce = Y (h => f => acc => ([x, ...xs]) => 
  (x === undefined)
    ? acc
    : h (f) (f (acc) (x)) (xs)
)
    
const mult = x => y => y * x

const factorial = x =>
  reduce (mult) (1) (range (1) (x))
  
console.log(factorial (5)) // 120
console.log(factorial (6)) // 720
console.log(factorial (7)) // 5040

答案 5 :(得分:0)

我会做这样的事情:

const range = (start, end) => Array.from(
  { length: end - start },
  (_, n) => start + n,
);

const product = (nums) => nums.reduce((a, b) => a * b);

const inc = (n) => n + 1;

const factorial = (num) => product(
  range(1, inc(num)),
);


const expect = (given) => ({
  toEqual(expected) {
    console.assert(given === expected, `${given} === ${expected}`);
  }
});

expect(factorial(5)).toEqual(120);
expect(factorial(6)).toEqual(720);