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

How can I write the factorial function with reduce and range?

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

使用范围函数和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 用于数组时,我如何使用 forEach?因为他们要我先使用 each 来编写阶乘函数,所以我需要使用基本案例,对吗?我还查看了 MDN 并尝试通过遵循他们的累加器 + currentValue 语法来理解 reduce 并提出了这个伪代码。

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

factorial(5)

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

当你说 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只是return初始值1。

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

我们可以使用提供给我们的范围方法来完成第一步。 range 方法 returns 一个包含最小值(含)和最大值(不含)之间的所有整数值的数组。例如,如果我们调用 range(1,5),它将 return [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 注意到这一点)

现在剩下的就是 return 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 之后添加这些行,但在你 return 它之前。

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

希望这对您有所帮助。

您可以使用 Array.apply 并为给定的开始值和结束值创建一个包含范围。

然后乘法归约。

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

只需Array.prototype.reduce()您就可以进行如下操作;

function factorial(a){
return Array(a[1]-a[0]).fill()
                       .reduce((r,_,i) => r *= a[0]+i+1, a[0] ? a[0] : 1);
}

console.log(factorial([0,10]));
console.log(factorial([2,5]));

这里还有很多其他答案可以提供解决问题的实用方法。相反,我的回答是故意不切实际的(如 JavaScript 中所写),但旨在教给您其他东西。

这个答案受到只有单参数、单表达式函数的 lambda 演算的影响。剖析这段代码会让你对高阶过程有深刻而深刻的理解。

我们将首先定义 Y 组合器,然后使用 Y 实现 rangereduce。那么我们终于可以实现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 == null
      ? 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

我会选择这样的东西:

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