A range of numbers in js - javascript

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

Related

Return a new array that is greater than its 2nd value

How to return a new array that its values are greater than its 2nd value. If the array that was passed to the function has less than two elements, function should return false.
For example,
greaterThanSecond([1,3,5,7])
should return [5, 7].
greaterThanSecond([0, -3, 2, 5])
should return [0, 2, 5].
greaterThanSecond([2])
should return false.
This is what I tried.
function valGreaterThanSecond(arr) {
for (let newArr of arr) {
if (newArr > arr[1]) {
return [newArr]
}else {
return false
}
}
}
You can try a one-liner:
[0, -3, 2, 5].filter((element, index, array) => element > array[1])
The filter function has 3 parameters:
The inspected elment
Index of the inspected element
The original array
The filter iterate through the array and you can compare to the original array's second element
function valGreaterThanSecond(arr) {
let resultArray = []
console.log(arr.length)
let checkValue = arr[1]
if(arr.length < 2)
return false
else
{
for(let i = 0 ; i < arr.length ; i++){
if(arr[i]!=checkValue && arr[i]>checkValue)
resultArray.push(arr[i])
}
return resultArray
}
}
console.log(valGreaterThanSecond([2]))
try this approach
You can try this
function greaterThanSecond(arr) {
if (arr.length < 2)
return false;
return arr.filter((item) => item > arr[1])
}
console.log(greaterThanSecond([0,-3,2,5]))
You can try this:
const greaterThanSecond = arr => {
if (arr.length > 1){
return arr.filter(e => e > arr[1])
}
return false
}
console.log(greaterThanSecond([1,3,5,7]))
In this function, at first you should check if the length of the array is not less than 2. Then we filter the array by checking if each number in the array is bigger than the second number and keep those ones in the array.
First let's try fixing your code before I am suggesting another approach.
function valGreaterThanSecond(arr) {
let newArr = [];
if (arr.length < 2) return false;
for (let elem of arr) {
if (elem > arr[1]) {
newArr = [...newArr, elem]
}
}
return newArr;
};
console.log(valGreaterThanSecond([1,3,5,7]));
The problem with your function is that once you found a number that is greater than the second element you immediately return it, thus exiting the function and returning this one element in an array, which is not what you want. If you found an element in the array that is not greater than the second element you immediately return false, which is not the behavior you want as well. In your example of [1,3,5,7] you will return false because 1 < 3 and you are out of the function at this point.
Different approach using reduce
I would like to suggest a different approach since there are a few answers using filter which is the first thing I would think about myself.
Here is a solution using the reduce function for arrays.
const greaterThanSecond = (arr) => {
if (arr.length < 2) return false;
const result = arr.reduce((acc, curr) => {
if (curr > arr[1]) return [...acc, curr];
return acc;
}, []);
return result;
}
console.log(greaterThanSecond([1,3,5,7]));

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

javascript function to find the second largest element in an array

I am completing the hackerrank's 10 days of javascript challenge. The question:
write a function to take an array as an argument and then return the second largest element in the array.
I have written the code but my code is returning the largest element and not the second largest as asked.
function getSecondLargest(nums) {
// Complete the function
var largest=nums[0];
for(let i=1;i<nums.length;++i)
{
if(nums[i]>largest)
largest=nums[i];
}
var large=nums[0];
for(let j=1;j<nums.length;++j)
{
if(large<nums[j]&&large<largest)
large=nums[j];
}
return large;
}
When input array nums={2,3,6,6,5} the result is coming 6 while expected output is 5. Please help and point out the errors in the function code below.
should not initialize large with first value var large=nums[0]; because it may appear the biggest value and won't work
should use nums[j]<largest instead of large<largest as mentioned above
I think don't need second loop as all checks can be done in first loop, and you can assign prev largest to large whenever you change it:
function getSecondLargest(nums) {
var largest = nums[0];
var large;
for (let i = 1; i < nums.length; ++i) {
if (nums[i] > largest) {
large = largest;
largest = nums[i];
} else if (nums[i] > large || typeof large === 'undefined') {
large = nums[i]
}
}
return large;
}
console.log(getSecondLargest([5,1-2,3]))
console.log(getSecondLargest([-5,1,-2,3]))
GET SECOND LARGEST
first, I create new array with unique values.
let arr = [...new Set(nums)];
second, sort value using built-in function .sort().
note : by default .sort() always sorts asciibetically, but for some testcase, it doesn't work. So, I put (a, b) => { return a - b } to make sure it will work properly.
arr = arr.sort((a, b) => { return a -b });
third, get the value from arr
let result = arr[arr.length - 2] || arr[0];
finally, return the result
return result
function getSecondLargest(nums) {
let arr = [...new Set(nums)];
//Javascript's array member method .sort( always sorts asciibetically.
arr = arr.sort((a, b) => { return a - b });
let result = arr[arr.length - 2] || arr[0];
return result
}
Just one minor change:
Use nums[j]<largest instead of large<largest in the second for loop
function getSecondLargest(nums) {
// Complete the function
var largest=nums[0];
for(let i=1;i<nums.length;++i)
{
if(nums[i]>largest)
largest=nums[i];
}
var large;
//To ensure that the selected number is not the largest
for(let j=0;j<nums.length;++j)
{
if (nums[j] !== largest){
large = nums[j];
break;
}
}
for(let j=1;j<nums.length;++j)
{
if(large<nums[j]&&nums[j]!=largest)
large=nums[j];
else
console.log(large)
}
return large;
}
var secondLargest = getSecondLargest([6,3,6,6,5]);
console.log("Second largest number", secondLargest);
If you want to avoid using library functions like #ifaruki suggests, this line
if(large<nums[j]&&large<largest)
should read
if (large<nums[j] && nums[j] < largest)
Sorting and picking the second or second-to-last value fails when there are duplicates of the highest value in the input array.
Another easiest logic is to remove duplicates from the array and sort.
let givenArray = [2, 3, 6, 6, 5];
let uniqueArray = [...new Set(givenArray)];
console.log("The second largets element is", uniqueArray.sort()[uniqueArray.length - 2]);
I know you had your question answered, just thought I would provide my solution for any future users looking into this.
You can use reduce to go through the array while remembering the two largest numbers so far.
You just make a simple reduction function:
function twoMax(two_max, candidate)
{
if (candidate > two_max[0]) return [candidate,two_max[0]];
else if (candidate > two_max[1]) return [two_max[0],candidate];
else return two_max;
}
And then you use it for example like this:
let my_array = [0,1,5,7,0,8,12];
let two_largest = my_array.reduce(twoMax,[-Infinity,-Infinity]);
let second_largest = two_largest[1];
This solution doesn't require sorting and goes through the array only once.
If you want to avoid using **sort method. I think here's the easiest logic to do that, which will also work in arrays where there's duplicates of largest integer exists.
function getSecondLargest(arr) {
const largest = Math.max.apply(null, arr);
for (let i = 0; i < arr.length; i++) {
if (largest === arr[i]) {
arr[i] = -Infinity;
}
}
return Math.max.apply(null, arr);
}
console.log(getSecondLargest([5, 7, 11, 11, 11])); //7

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 can't properly understand how recursive functions work

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

Categories