Stacks and recursive functions - javascript

I hope this is not a repeated question-- though I couldn't find much help on this.
I am practicing recursive functions (I'm a newbie), and I'm trying to multiply each number in an array. Sort of like a factorial. I have this code, but it is only returning undefined as a result.
Here is the code:
var stack = [];
function countDown(int) {
stack.push(int);
if (int === 1) {
return 1;
}
return countDown(int - 1);
}
function multiplyEach() {
// Remove the last value of the stack
// and assign it to the variable int
int = stack.pop();
x = stack.length;
// Base case
if ( x === 0 ) {
return;
}
// Recursive case
else {
stack[int - 1] = int * stack[x - 1];
return multiplyEach(int);
}
}
// Call the function countDown(7)
countDown(7);
// And then print out the value returned by multiplyEach()
console.log(multiplyEach());
Thank you so much for any insight.
Cheers!

The first thing to address is that your multiplyEach() function should have a parameter named int, from the looks of it. The approach you're using might be better suited to a different technique, but we'll get to that.
Next, in multiplyEach(), there are two possible paths:
The stack still has elements, in which case we multiply the new top value on the stack by the old one and move on to another run of multiplyEach.
The stack is empty, and we just return.
The problem here is that we aren't actually returning the final stack value, or leaving it on there to access later. We've effectively lost it, so what is the function outputting?
In many languages, we would have defined a return type for this function, either void for no value, or int for returning the multiplied value. However, in Javascript, there is no such thing as a function that doesn't return a value; "nothing" in JS is represented as undefined. When you return multiplyEach(), you're pushing another call of it onto the call stack, and waiting for an actual return value... which ends up being return;, which JS interprets as return undefined;. Again, in most languages, there would be some form of error, but not in JS! Let's look at two possible implementations:
The custom stack you use:
// your stack is fine, so we'll skip to the meat
function multiplyEach() {
var int = stack.pop(), x = stack.length;
stack[x - 1] *= int;
if(x < 2) // to multiply, we need at least two numbers left
return;
multiplyEach();
}
//...
multiplyEach();
console.log(stack[0]);
With a parameter, and using a list:
function multiplyEach(index) {
var int = list[index];
if(index == 0)
return int;
return int * multiplyEach(index - 1);
}
//...
console.log(multiplyEach(list.length - 1));
They're both different ways of implementing this recursively; all recursion inherently requires is for a function to call itself. Another possibility would have been having a parameter store the total, instead of multiplying the return values like in option 2; that's called tail recursion.
EDIT: noticed the base case for option 1 was in the wrong place, so I moved it. It should work now.

Recursively you can do this way:
function multiplyEach(arr, size) {
return size === 0 ? arr[size] : arr[size] * multiplyEach(arr, size - 1);
}
var array = [1, 2, 3, 4, 5, 6, 7, 8, 9];
console.log(multiplyEach(array, array.length - 1));
But you can do it using the native method reduce, then you could do simply this:
console.log([1, 2, 3, 4, 5, 6, 7, 8, 9].reduce(function(a, b) { return a * b; }));
ES6 version:
console.log([1, 2, 3, 4, 5, 6, 7, 8, 9].reduce((a, b) => a * b));
I hope it helps.

There are times recursion is better suited to solve a problem and there are times iteration is better suited to solve a problem.
Recursion is better suited for performing an action until a condition is met then exiting, similar to a while loop.
Iteration is better suited for performing an action N number of times then exiting, similar to a for loop.
In our case, we want to input an array and output the product of all elements of that array. In other word, we want to perform N - 1 multiplications where N is the number of elements in the array. Since we know the number of operations we want to perform we should solve our problem with iteration which is done below.
var arr = [1, 2, 3]
var result = multiplyEach(arr)
console.log(result)
// -> 6
function multiplyEach(arr) {
var result = 1
arr.map(function(value) {
result *= value
})
return result
}
Keep in mind though that the above is an approximate rule of thumb because sometimes recursion will be a more elegant solution than iteration. Here's the simple, recursive, and elegant implementation of the real factorial.
function factorial(value) {
return 1 === value ? 1 : value * factorial(value - 1)
}
The iterative implementation of factorial is not as pretty in while loop form nor for loop form.
function factorial(value) {
var result = 1
while (value > 0) {
result *= value
value--
}
return result
}
function factorial(value) {
var result = 1
for (var i = 0; i < value; i++) {
result *= value
}
return result
}

I think the main issue is that you do not have an argument in the multiplyEach() definition, but you attempt to call it with one inside the function.
Something like this works:
var stack = [1, 2, 3, 4, 5, 6, 7];
function multiplyEach(arr) {
if (arr.length == 0) {
return 1;
} else {
return arr.pop() * multiplyEach(arr);
}
}
console.log(multiplyEach(stack));

The base case in the recursive function multiplyEach() returns undefined.
That's where your problem lies.
A simple fix would be:
var stack = [];
var multipliedStack = [];
function countDown(int) {
stack.push(int);
if (int === 1) {
return 1;
}
return countDown(int - 1);
}
function multiplyEach() {
// Remove the last value of the stack
// and assign it to the variable int
int = stack.pop();
x = stack.length;
// Base case
if ( x === 0 ) {
return multipliedStack.reverse();
}
// Recursive case
else {
multipliedStack.push(int * stack[x - 1]);
return multiplyEach(int);
}
}
// Call the function countDown(7)
countDown(7);
// And then print out the value returned by multiplyEach()
console.log(multiplyEach());
I don't fully get what you mean by "sort of like a factorial"? What exactly is the function supposed to do?
To understand recursion you need to wrap your head around what a recursive base case is and also I think you need to revise push() and pop() which are not used in a proper way in your code.
Recursive functions are usually abit confusing if you are used to iteration, keep trying and you'll get comfortable with it rather quick.

Related

Problem when learning forEach method in Javascript

I start learning Javascript since a week and I try to do some practice about the loop,
So I try to make a function which each time I call it, I doubled the numbers in an array.
I manage to do it with the classic "for" loop like this as an example:
var numbers = [2, 5, 37, 500, 75];
function getDoubled() {
for (var i = 0; i < numbers.length; i++) {
(numbers[i] = numbers[i] * 2);
}
}
So here the numbers in my array doubled each time I call the function getDoubled(); and now I try to do the same with forEach method.
var numbers = [2, 5, 37, 500, 75];
function getDoubled(array) {
array.forEach(function(number) {
(number = number * 2);
})
}
But I wasn't able to change the array when I call the function getDoubled(numbers), however if I test with console.log(number*2), it worked in the console, so I wasn't able to figure it out the mistake.
Reassigning an identifier has no side-effects. That is, doing someVariable = somethingNew will only result in a discernable change in how your script runs if something else references the someVariable which has the new value in it. Here, the number = number * 2 does nothing because nothing is referencing the doubled number variable; reassigning the parameter doesn't do anything to the array.
The way to do this with forEach would be to reassign the index in the array, just like in the for loop.
var numbers = [2,5,37,500,75];
function getDoubled(array) {
array.forEach(function(number, i){
array[i] = number * 2;
})
}
getDoubled(numbers);
console.log(numbers);
Alternatively, a nicer approach would be to construct a new array with the changed values, which can be done with .map, which creates a new array by performing a callback on every element of the original array - that way you don't have to look at the (unimportant) indicies to get the output you want.
var numbers = [2,5,37,500,75];
function getDoubled(array) {
return array.map(num => num * 2);
}
console.log(getDoubled(numbers));

Return Command for Callback Functions

function twoSum(numbers, target) {
var result = [];
numbers.forEach(function(value, index) {
return numbers.forEach(function(value2, index2) {
if (value + value2 === target) {
result.push(index, index2);
return result;
}
})
})
return result;
}
twoSum([1, 2, 3], 4);
//Output - [ 0, 2, 1, 1, 2, 0 ]
Hi - I'm working on a particular codewars problem and I seem to be misunderstanding the usage of return for callback functions. In this particular problem I just want to find the first two sums of numbers that equal the target and push those index values into result. I don't want to keep iterating through my function after that - meaning I only want the first pair that's found. My current output gives me all the index values for the target sum. Not just the first 2. It seems I am not using my return commands correctly. My current line of thought is that return result returns a value to my nested callback of parameters (value2, index2). That result is then returned to my outside function of (value,index). Why does my loop not cease after that return?
It doesn't end because .forEach cannot be terminated early. forEach is not paying any attention to the values you return. If you want to terminate early you'll need to use a different approach.
If you want to stick with array methods, there are .some and .every. The former continues until a run of your function returns true, and the latter continues until a run of your function returns false. These are meant for doing compound OR's and compound AND's with every element of the array, but they can kinda be used for your case too.
numbers.some(function(value, index) {
return numbers.some(function(value2, index2) {
if (value + value2 === target) {
result.push(index, index2);
return true;
}
return false;
})
})
Or you could use a standard for loop, with the break keyword when you want to stop the loop.
Beside the not working return statement for a outer function, you need to take a different approach which uses only a single loop and an object for storing the index of the found value.
function twoSum(numbers, target) {
var indices = {};
for (let i = 0; i < numbers.length; i++) {
const number = numbers[i];
if (number in indices) return [indices[number], i];
indices[target - number] = i;
}
}
console.log(twoSum([1, 2, 3], 4));

Recursion explanation countdown function with multiple methods

I'm trying to write a recursion that will create a countdown array. The function should take an array in the myArray parameter and append the numbers n through 1 based on the n parameter. For example, calling this function with n = 5 will pad the array with the numbers [5, 4, 3, 2, 1] inside of it. Your function must use recursion by calling itself and must not use loops of any kind.
Seems to be multiple ways to write a recursion, is there a generally accepted and easily readable method?
function countdown(myArray, n){
if (n>=1) {
myArray = countdown(myArray, n-1);
myArray.unshift(n);
}
return myArray;
}
function countdown(myArray, n){
if (n<=0) {
return;
} else {
myArray.push(n);
countdown(myArray,n-1);
}
}
If I enter countdown(myArray, 5), both functions returns an array called myArray = [5,4,3,2,1].
The bottom function has a typical base case... while the top function doesn't? I'm more comfortable writing it using the bottom method but I'm kind of confused why it works. Wouldn't bottom function be calling until it gets to countdown(myArray,0), then return and start going back up the stack. So wouldn't it start with myArray.push(1) before it works its way back up the stack causing the answer to be [1,2,3,4,5] instead of [5,4,3,2,1]?
If you add an else branch into the first function, and move the return into both branches (thus not changing the meaning):
if (n>=1) {
myArray = countdown(myArray, n-1);
myArray.unshift(n);
return myArray;
} else {
return myArray;
}
Now invert the if statement (swapping both the condition and the branches):
if(n <= 0) {
return myArray;
} else {
myArray = countdown(myArray, n-1);
myArray.unshift(n);
return myArray;
}
So as you can see, both functions are equal, as they can be transformed i to each other without making breaking changes (however one does return myArray while the other one does not).
Now wheres the base case in the first function? Well, if n is 0 or less, it does not enter the if and as the recursive call is inside the ifs branch ... it does not call itself again.

Using some, but still need to use the index of the array

I currently have a function that allows me to test if something a piece (for connect 4) is in an array, as well as 1, 2, and less respectively. If all 4 numbers are in the array are present, then it returns true. This works.
What I am trying to do is make it so I can use .some, so I can test if the array contains any cases of having a number, and again 3, 2, and 1 less than the number tested.
Right now it will test an individual piece, but I don't know how to get it to grab onto the array to check the index of the individual element it is testing.
Thank you for any responses/Ideas.
const testPieces = [1, 2, 3, 4]
const fourInARow = function(piece, array) {
for (var i = piece; i >= piece - 3; i--) {
if (array.indexOf(i) === -1) {
return false
}
}
return true
}
testPieces.some(fourInARow) // The piece that I don't know how to make work
Calling .some on your testPieces array will pass in each element of the array to the fourInARow function as the piece argument. It will not pass in your second array argument.
You need to provide a function to the .some call that already knows about the array for testing. You can do this by returning a function from the function e.g.
const fourInARow = function(array) {
return function(piece) {
for (var i = piece; i >= piece - 3; i--) {
if (array.indexOf(i) === -1) {
return false
}
}
return true
};
}
The array you are testing can now be passed to the .some call like this;
testPieces.some(fourInARow([1,2]));
The returned function has created a closure which retains a reference to the test array [1,2] which is then compared to the piece argument supplied by the call to .some.
Just wondering why not flip the logic to start from the other side and use instead of some every with includes?
const testPieces = [1, 2, 3, 4]
const inARow = (arr, base) => arr.every((x) => base.includes(x))
console.log(inARow([4,3,1,2], testPieces))
console.log(inARow([5,2,1], testPieces))
It becomes one line, it does not care about the order etc. Let me know if I am missing something ...

Javascript: Write a function that takes in a number, and returns an array with that number in it that many times

I'm a complete newbie to programming and mathematical concepts (took Math 101 in college) so I'm struggling with this problem:
Write a function that takes in a number, and returns an array with that number in it that many times.
Here's the code I've got so far:
function numReturn(x) {
var newArray = [];
if (typeof x === "number") {
return newArray.push[x]* x;
} else {
return null;
}
}
Here's my thought process:
Create a function that can take in a number, x.
Within that function, create a blank array so you can push values to it later.
Check if the typeof value entered in for x is a number. If it is, return it pushed to the end of the blank array. Otherwise, return null.
When I put this in the Javascript console and plug a value in, it comes back undefined. Anyone have some pointers for me?
function a(i) {
var a = new Array(i);
return a.fill(i);
}
or return new Array(i).fill(i);, for short. Test:
a(4)
// --> [4, 4, 4, 4]
Array.prototype.fill() is an ES6 method and is not yet universally implemented. Chrome and Firefox have it, IE does not - but there is a polyfill available.
Compare: http://kangax.github.io/compat-table/es6/#test-Array.prototype_methods_Array.prototype.fill
In order to do something an arbitrary number of times, one uses a loop. There are several loops, but here the for loop is most appropriate.
A for loop has the following structure:
for(var i = 0; i < x; i++) {
// ^initializer
// ^condition
// ^increment
//body
}
The initializer is the first thing that is done when entering the loop. IN this case, it means a variable named i is set to 0. Then the condition x is checked. If the condition i < x holds, the loop is executed: the body is executed. After the body is executed, the increment is performed (here i++), and then the condition is rechecked, if the condition still holds, the loop is executed again, and so on.
You can apply this concept as follows:
function numReturn(x) {
var newArray = [];
if (typeof x === "number") {
for(var i = 0; i < x; i++) {
newArray.push(x);
}
return newArray;
} else {
return null;
}
}
This: newArray.push[x]* x does not push x times. The * operator just multiplies numbers, always and only. You want to push x times, so use a for like this:
for (var i = 0; i < x; i++ )
newArray.push(x);
and then return newArray.
Taking from answer of Most efficient way to create a zero filled JavaScript array?
function numReturn(x){
return Array.apply(null, Array(x)).map(Number.prototype.valueOf,x);
}
console.log(numReturn(10)); // [10, 10, 10, 10, 10, 10, 10, 10, 10, 10]
var n = 7
var result = Array.apply(null, {length: n}).map(function(){return n})
// Demo output
document.write(JSON.stringify(result))
As function:
function numReturn(x) {
if (typeof x === "number") {
return Array.apply(null, {length: n}).map(function(){return n})
} else {
return null;
}
}

Categories