i can't properly understand how recursive functions work - javascript

So I debugged this function using the browser debugger to see how it works:
function rangeOfNumbers(startNum, endNum) {
console.log(`called with start: ${startNum} end: ${endNum}`)
if (startNum === endNum) return [startNum];
else if (startNum > endNum) return;
else {
let arr = rangeOfNumbers(startNum + 1, endNum);
arr.unshift(startNum);
return arr;
}
};
console.log(rangeOfNumbers(0, 4))
So after the (let arr) part returns an array with [startNum], (startNum) is equal to 4 which is (endNum) (from the condition I set at first), from there (startNum) starts reducing by one and going from 3 till the (startNum) I set as an argument (0). How does this happen exactly? What makes it reduce every time?

lets call the rangeOfNumbers() function ron(). Your code executes as follows:
ron(0,4)
ron(1,4)
ron(2,4)
ron(3,4)
ron(4,4)
at:
ron(4,4) it returns 4
now we just work backwards and build arr up one element at a time. Also you don't need the else if in your code.

I've added some logs of what's happening in main branch of code. As you can see, while the code is called sequentially, incrementing startNum by one each time, the result of each call is handled in reverse:
The call to rangeOfNumbers(4, 4) returns [4]
The call to rangeOfNumbers(3, 4) receives the [4] from step 1 and adds 3 to the beginning of the array (unshift).
The call to rangeOfNumbers(2, 4) receives the [3,4] from step 2 and adds 2 to the beginning of the array
The call to rangeOfNumbers(1, 4) receives the [2,3,4] from step 3 and adds 1 to the beginning of the array
The call to rangeOfNumbers(0, 4) receives the [1,2,3,4] from step 4 and adds 0 to the beginning of the array
And that's it...
function rangeOfNumbers(startNum, endNum) {
if (startNum === endNum) {
let arr = [startNum];
console.log('result of call with startNum:', startNum, ', endNum:', endNum, arr);
return arr;
} else if (startNum > endNum) {
return;
} else {
let arr = rangeOfNumbers(startNum + 1, endNum);
console.log('result of recursive call with startNum + 1:', startNum + 1, ', endNum:', endNum, arr);
arr.unshift(startNum);
console.log('after adding startNum to beginning of array:', startNum, arr);
console.log('result of call with startNum:', startNum, ', endNum:', endNum, arr);
return arr;
}
};
console.log('final result', rangeOfNumbers(0, 4));
.as-console-wrapper { max-height: 100% !important; top: 0; }

Related

A range of numbers in js

So I wanted to make a recursive function that pushes a range of numbers inside of an array.
So I did the following:
function rangeOfNumbers(startNum, endNum) {
let arr = [];
if (startNum != endNum) {
rangeOfNumbers(startNum++, endNum);
arr.push(startNum);
} else {
arr.push(endNum);
}
return arr;
};
console.log(rangeOfNumbers(1, 5));
so the way I think that should work is that in each iteration startNum should be +1 and should be pushed inside of the array and when startNum gets to endNum's value in this case 5 we should push endNum and end the recursion, why is my logic faulty, cuz what happens now is that my function exceeds the maximum call stack.
Another thing I tried was:
function rangeOfNumbers(startNum, endNum) {
let arr = [];
if (startNum == endNum) {
return arr.push(endNum);
} else {
rangeOfNumbers(startNum++, endNum);
arr.push(startNum);
}
return arr;
};
still exceeds the callstack, why does that happen? :(
You are redefining your arr variable on every call, and never using the arrays returned from deeper calls. You can either pass a single array reference as Basto does in their answer, or you can run through the recursion and only define the array on the terminal call and then unshift() each startNum into the returned array.
function rangeOfNumbers(startNum, endNum) {
const arr = startNum < endNum ? rangeOfNumbers(startNum + 1, endNum) : [];
arr.unshift(startNum);
return arr
};
console.log(rangeOfNumbers(1, 5));
unshift() is quite slow though. You can alter the logic to use push() by decrementing 'endNum' instead of incrementing 'startNum', and pushing 'endNum' on each call.
function rangeOfNumbers(startNum, endNum) {
const arr = startNum < endNum ? rangeOfNumbers(startNum, endNum - 1) : [];
arr.push(endNum);
return arr
}
console.log(rangeOfNumbers(1, 5))
Or using spread syntax (...)
function rangeOfNumbers(startNum, endNum) {
return startNum <= endNum
? [startNum, ...rangeOfNumbers(startNum + 1, endNum)]
: [];
}
console.log(rangeOfNumbers(1, 5));
You are only returning the array from the first iteration.
You need to make the array one of your arguments on your recursive function so all the pushes are into the same array
function rangeOfNumbers(startNum, endNum, arr =[]) {
if(startNum < endNum) {
arr.push(startNum);
rangeOfNumbers(startNum + 1, endNum, arr);
}else{
arr.push(endNum);
}
return arr;
};
Edit:
You probably also want to call the recursion after the push so they are all in order.
And I also changed the comparison operator to a < to prevent stack overload if the function is used wrong.
You have to put the array in parameters :
let arr = [];
function rangeOfNumbers(startNum, endNum, arr) {
if (startNum !== endNum) {
arr.push(startNum);
rangeOfNumbers(startNum + 1, endNum, arr);
} else {
arr.push(endNum);
}
return arr;
}
console.log(rangeOfNumbers(1, 5, arr));

returning an array using recursion

I'm pretty new to recursion and Im having trouble returning the value I want into an array. I have a simple function called countDown which needs to take in an argument of type integer in this case the parameter/argument is the letter (n). and I want to count backwards starting from the number (n) all the way to 1. so for example if I pass in the number 4 I would like to return [4, 3, 2, 1] and I need to do this recursively. I believe I have gotten close because in my code I simply put a console.log(n) and I can see now the numbers are printing out 4, 3, 2, 1 however I need to return these numbers in an array and I am pretty lost. I'm familiar with .push() but that doesn't seem to work and I have tried .concat() but I'm not able to get it to work either. Any help is much appreciated!
function countDown(n) {
if (n < 1) {
return [];
} else {
console.log(n);
let j = countDown(n - 1);
}
}
countDown(4);
You are indeed pretty close. There are going 2 things wrong in your snippet.
You do not return a value if n is not smaller than 1 (the else scenario).
You do log n, but don't add it to the result.
Without changing a lot, a solution might look like this:
function countDown(n) {
if (n < 1) {
return [];
} else {
// get the countdown of n - 1
const ns = countDown(n - 1);
// add the current n in front
ns.unshift(n);
// return the list
return ns;
}
}
console.log(countDown(4));
Make sure you return something in every case!
You're doing it for the base case (return []), but you need to return something that includes the recursive call in other cases (return // something that uses countDown(n-1)).
function countDown(n) {
if (n < 1) return [];
return [n, ...countDown(n-1)];
}
console.log(countDown(4));
You appear to be nearly there, but when using recursion state will need to be passed to the next iteration.
So below is an example where the arr parameter if left blank will create the initial array, and then the recursive part can just keep passing this down.
function countDown(n, arr) {
if (!arr) arr = [];
if (n < 1) {
return arr;
} else {
arr.push(n);
return countDown(n -1, arr);
}
}
console.log( countDown(4) );
Is this does what you want?
let arr = [];
function countDown(n) {
if (n < 1) {
return [];
} else {
arr.push(n);
countDown(n - 1);
}
}
countDown(4);
console.log(arr);
Try something like this
function countDown(n, a = []) {
if (n < 1) {
console.log(a);
return a;
} else {
a.push(n);
let j = countDown(n - 1,a);
}
}
countDown(4);

Use Recursion to Create a CountdownPassed (JS Algorithm)

Question
We have defined a function called countdown with one parameter (n). The function should use recursion to return an array containing the integers n through 1 based on the n parameter. If the function is called with a number less than 1, the function should return an empty array. For example, calling this function with n = 5 should return the array [5, 4, 3, 2, 1]. Your function must use recursion by calling itself and must not use loops of any kind.
function countdown(n, newArr = []){
if(n == 1){
return newArr;
}
newArr.push(n);
return countdown(n - 1)
}
console.log(countdown(5));
My Question
Is there a way to fix this code so that it works?
I can provide an alternative solution, but I do not understand it:
function countdown(n) {
if (n < 1) {
return [];
} else {
const arr = countdown(n - 1);
arr.unshift(n);
return arr;
}
}
The problem is that you do not pass on the array to the recursive call, so each recursive execution creates a new, empty array. As a consequence, it does not return the array that had a value pushed to it, but the new, empty one that is coming back from the recursive calls.
Secondly, you never push value 1 to the array. So it would be better to stop the recursion at 0 instead of 1.
So taking those two fixes, you get this:
function countdown(n, newArr=[]) {
if (n <= 0) {
return newArr;
}
newArr.push(n);
return countdown(n - 1, newArr)
}
console.log(countdown(5));
Your alternative solution is clean, because it does not need to pass an array as argument. It uses the returned array to add the next value to it (in front of it). It would have my preference.
To understand how it works, print out the intermediate values:
function countdown(n) {
if (n < 1) {
console.log("At the end of recursion. Creating and returning an empty array.");
return [];
} else {
const arr = countdown(n - 1);
console.log("Got the following array back from the recursive call:");
console.log(JSON.stringify(arr));
arr.unshift(n);
console.log("Prefixing it with " + n + " and returning the result:");
console.log(JSON.stringify(arr));
return arr;
}
}
var result = countdown(5);
yes, you can modify your solution like that
function countdown(n){
if(n == 0){
// stop the function at 0 so it will not be included in the array
return [];
}
// concat the value of n as an array with the value less than it
return [n].concat(countdown(n - 1))
}
console.log(countdown(5));
the problem in your solution is that your array initialized as an empty array every time so the final answer will be an empty array
You need to hand over the result array for the recursive call. And you need to check if no value is left, ten return the result array.
function countdown(n, result = []) {
if (n < 1) return result;
result.push(n);
return countdown(n - 1, result);
}
console.log(countdown(5));
As another approach, you could return an array and for the exit condition take the final value, otherwise take n and the spreaded result of the recursive call.
function countdown(n) {
if (n < 1) return [];
return [n, ...countdown(n - 1)];
}
console.log(countdown(5));
At this point we will create the countdown function which call itself and called recursion.
function countdown(n) {
if (n < 1) {
return [];
} else {
console.log(n, "before calling");
const arr = countdown(n - 1);
console.log(n, "after calling");
return arr;
}
}
console.log(countdown(5));
And now when we know that the "before calling" is place where n is decrease and the "after calling" is place where n is increase, based on that we can do this.
const arr = [];
function countdown(n) {
if (n < 1) {
return arr;
} else {
arr.push(n);
return countdown(n - 1);;
}
}
console.log(countdown(5));

I don't understand this case of recursion

This is a solution from this exercice on FreeCodeCamp
function countdown(n) {
if (n < 1) {
return [];
} else {
const arr = countdown(n - 1);
arr.unshift(n);
return arr;
}
}
I understand the concept of recursion. I get that the function countdown will be repeated until n < 1 and the following command arr.unshift(n) will be executed once all possible values of n will be evaluated. What bugs me is that I don't get when or how const arr becomes and array.
What bugs me is that I don't get when or how const arr becomes and
array.
See the base case returns an empty array? This is where it all starts, thanks to that you are able to proceed with the array structure once the code returns from the recursive calls.
Code explanation
Unshift will append at zeroth index the LIFO, meaning
the last which was in is 1 and it will be added to the array, after that the array will add number 2 at zeroth index and at second index you'll have number 1, after that number 3 will be added at zeroth index, second index will be number 2, and last index will contain number 1. Now you see the pattern...
Try to console.log in between
function countDown(n) {
if (n < 1) {
return [];
} else {
const countArray = countDown(n - 1);
console.log(n)
countArray.unshift(n);
return countArray;
}
}
console.log(countDown(5));
If you are more used to ES6+ syntax, add the first element n at the first position of the array and de-structure the rest.
function countDown(n) {
if (n < 1) {
return [];
} else {
const countArray=[n,...countDown(n - 1)];
return countArray;
}
}
console.log(countDown(5));
And at last, you can make it a one liner with ternary operators:
const countDown = (n) => n < 1 ? [] : [n, ...countDown(n - 1)];
console.log(countDown(5));
Let's follow the pattern for a relatively simple call. Here again is the function:
function countdown(n) {
if (n < 1) {
return [];
} else {
const arr = countdown(n - 1);
arr.unshift(n);
return arr;
}
}
Say you call countdown(2):
Loop 1:
1a) n is not less than 1
1b) an arr is initialized and set to countdown(1)
Loop 2:
2a) n is not less than 1
2b) an arr is initialized and set to countdown(0)
Loop 3:
3a) n is less than 1
3b) an empty array is returned to loop 2
arr is []
Loop 2 cont.
2c) arr.unshift adds the number 2 to the start of the array.
arr is [2]
2d) arr is returned to loop 1
Loop 1 cont.
1c) arr.unshift adds the number 1 to the start of the array.
array is [1,2]
1d) arr is returned to function call
So if you wrote let result = countdown(2) and console.log(result), you will get: [1,2]
What bugs me is that I don't get when or how const arr becomes and
array.
Look at steps 3b, 2b, and 2c:
3b) an empty array is returned to loop 2
2b) an arr is initialized and set to countdown(0)
2c) arr.unshift adds the number 2 to the start of the array.
An empty array is set to const arr, then the number 2 is added to that array.
Now look at steps 2d and 1c:
2d) arr is returned to loop 1
1c) arr.unshift adds the number 1 to the start of the array.
That array is set to a new array like this (const arr = [2]) and the number 1 is added to that array. Finally in 1d, that new array is returned to the expression that called the function. For every recursive loop you have something like this:
const arr = something
new const arr = old const arr

Function to Sort an Array, Insert a Value into that Array and Return the Lowest Index

I am working on a JavaScript challenge that asks you to write a function to: "Return the lowest index at which a value (second argument) should be inserted into a sorted array (first argument). For example, where([1,2,3,4], 1.5) should return 1 because it is greater than 1 (0th index), but less than 2 (1st index)."
The hint indicates to use a built-in ".sort()" method that I am unfamiliar with before this challenge. below is what I have so far and I think I am far off.
function where(arr, num) {
arr.push(num).sort(function(a,b){return a-b;});
return arr.indexOf(num);
}
console.log(where([40, 60], 50)); // returns "unexpected identifier"
Split the two statments.
function where(arr, num) {
arr.push(num);
arr.sort(function(a, b) {
return a - b;
});
return arr.indexOf(num);
}
console.log(where([40, 60], 30)); // 0
console.log(where([40, 60], 50)); // 1
console.log(where([40, 60], 70)); // 2
As rightly put by #Xufox, push returns the new length of the array and not the array itself.
Reorder your code as shown:
function where(arr, num) {
arr.push(num); // Carry out push operation.
arr.sort(function(a,b){return a-b;}); // Sort array.
return arr.indexOf(num); // Return index of 'num'.
}
console.log(where([40, 60], 50));
function where(arr, num) {
let index = arr.sort((x,y) => x-y)
.find(x => num <= x);
return index === undefined? arr.length: arr.indexOf(index);
}
function getIndexToIns(arr, num) {
arr.sort(function(a, b) {
return a - b;
});
var i=0;
while(num>arr[i])
i++;
return i;
}

Categories