Reputation: 264
The question is the following :
Write a function called productOfArray which takes in an array of numbers and returns the product of them all.
Why does this solution not work:
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)
}
And is there a better way to solve this recursively without altering the array?
Upvotes: 1
Views: 88
Reputation: 28981
is there a better way to solve this recursively without altering the array?
Honestly, recursion is not the best way to go about this. Using Array#reduce
is the idiomatic way of handling this:
arr.reduce(
(a, b) => a * b, // apply the operation
1 // use the identity element for the operation
) // which is the number 1 for multiplication
However, since you're asking for how to do it with recursion without modifying the array, here it is:
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);
Using Array#slice
makes a new array, so the initial one is untouched:
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);
And because we terminate with an array of zero elements, we exit after there is nothing left to multiply. With an input of [2, 3, 4]
the recursion will effectively evaluate 2 * 3 * 4 * 1
.
Note: this implementation does mean that productOfArray([])
(empty array) produces 1
. Whether this is acceptable or not may vary - it's a nice neutral value. The benefit is that you do get to finish the recursion with an empty array, otherwise with a terminal condition of arr.length === 1
, passing an empty array will result in infinite recursion. Unless it's handled as yet another condition:
if (arr.length === 0) {
return 1; //or zero? Or whatever makes sense
}
if (arr.length === 1) {
return arr[0];
}
However, just handling one more condition basically doubles the code of the function. And assuming you want to return 1
anyway, it's unnecessary code. However, it might be worth doing if you want to consider the product of an empty array to be zero.
Finally, the same logic can be implemented using a destructuring of the function's parameter instead of using .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);
As Scott Sayuet points out in a comment the above can even be shortened to:
const prod = ([x, ...xs] = []) =>
x == undefined ? 1 : x * prod (xs)
Upvotes: 2
Reputation: 3302
You are poping before putting it somewhere. Put it in tmp variable and then multiply it.
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]));
Upvotes: 0
Reputation: 31682
arr[last]
will be undefined
because the number at that index does not exist anymore because of the pop
call. Also, pop
will return the item it removes, so you don't need the indexing at all, just use what pop
returns like so:
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
Upvotes: 2