问题如下:
编写一个名为productOfArray的函数,该函数接受一个数字数组并返回所有数字的乘积。
为什么这个解决方案不起作用:
function productOfArray(arr){
if (arr.length === 1) {
return arr[0];
}
if (arr.length > 1){
var last = arr.length - 1
arr.pop()
return arr[last] * productOfArray(arr)
}
有没有更好的方法可以在不改变数组的情况下递归地解决这个问题?
有没有更好的方法可以在不改变数组的情况下递归解决这个问题?
老实说,递归并不是最好的方法。使用Array#reduce
是处理此问题的惯用方法:
arr.reduce(
(a, b) => a * b, // apply the operation
1 // use the identity element for the operation
) // which is the number 1 for multiplication
然而,由于您询问的是如何在不修改数组的情况下使用递归,因此它是:
function productOfArray(arr) {
if (arr.length === 0) { //terminal condition
return 1; // produce the identity element for multiplication
}
return arr[0] //first element
* //multiplied by
productOfArray(arr.slice(1)) //the rest of the elements multiplied
}
const arr1 = [2, 3, 4];
const arr2 = [3, 3, 10];
const arr3 = [5, 3, 7];
console.log("2 * 3 * 4 =", productOfArray(arr1));
console.log("3 * 3 * 10 =", productOfArray(arr2));
console.log("5 * 3 * 7 =", productOfArray(arr3));
console.log("arr1 unchanged:", arr1);
console.log("arr2 unchanged:", arr2);
console.log("arr3 unchanged:", arr3);
使用Array#slice
生成一个新数组,因此初始数组不受影响:
const input = [2, 3, 4];
const result1 = input.slice(1);
const result2 = result1.slice(1);
const result3 = result2.slice(1);
console.log("result1:", result1);
console.log("result2:", result2);
console.log("result3:", result3);
因为我们终止于一个零元素的数组,所以我们在没有剩余的乘法之后退出。有了[2, 3, 4]
的输入,递归将有效地评估2 * 3 * 4 * 1
。
注意:此实现并不意味着productOfArray([])
(空数组(生成1
。这是否可以接受可能会有所不同——这是一个不错的中性值。好处是do可以用空数组完成递归,否则在arr.length === 1
的终端条件下,传递空数组将导致无限递归。除非将其作为另一种情况处理:
if (arr.length === 0) {
return 1; //or zero? Or whatever makes sense
}
if (arr.length === 1) {
return arr[0];
}
然而,只处理一个条件基本上会使函数的代码加倍。假设您无论如何都要返回1
,那么这是不必要的代码。然而,如果您想将空数组的乘积视为零,则可能值得这样做。
最后,可以使用函数参数的析构函数来实现相同的逻辑,而不是使用.slice()
function productOfArray([head, ...tail]) {
if (head === undefined) {
return 1;
}
return head * productOfArray(tail);
}
const arr1 = [2, 3, 4];
const arr2 = [3, 3, 10];
const arr3 = [5, 3, 7];
console.log("2 * 3 * 4 =", productOfArray(arr1));
console.log("3 * 3 * 10 =", productOfArray(arr2));
console.log("5 * 3 * 7 =", productOfArray(arr3));
console.log("arr1 unchanged:", arr1);
console.log("arr2 unchanged:", arr2);
console.log("arr3 unchanged:", arr3);
正如Scott Sayuet在评论中指出的那样,上述内容甚至可以缩短为:
const prod = ([x, ...xs] = []) =>
x == undefined ? 1 : x * prod (xs)
arr[last]
将是undefined
,因为该索引处的数字由于pop
调用而不再存在。此外,pop
将返回它删除的项目,因此您根本不需要索引,只需使用pop
返回的内容即可:
var last = arr.pop(); // remove the last number from the array and store it in the variable 'last'
return last * productOfArray(arr); // use it here
在将其放在某个位置之前,您正在弹出。将其放入tmp变量中,然后将其相乘。
function productOfArray(arr) {
if (arr.length === 1) {
return arr[0];
}
if (arr.length > 1) {
var last = arr.length - 1;
var tmp = arr[last];
arr.pop();
return tmp * productOfArray(arr);
}
}
console.log(productOfArray([2, 5, 1, 2]));