Trying to understand recursion in JS... check my simple code - javascript

I am trying to wrap my head around recursive functions. I've tried a number of entry level exercises with no success. For example, I put this code into JS fiddle. I intended for it to take the sum of all numbers from 1 to n.
function sumAll(n) {
if (n == 1 ) {
return 1;
} else if (n > 1) {
return sumAll(n--) + n;
}
}
console.log(sumAll(3));
feeding 3 to the function should give me '6'. I get an error, though.

The -- suffix operator will evaluate to the original value of n, and the subtraction from n will happen afterwards (which is also not desired as you still want to do + n). That means the recursive call gets the same value for n as the caller, and so you don't get closer to the end...
Don't use -- here, but -1:
function sumAll(n) {
if (n == 1 ) {
return 1;
}
else if (n > 1) {
return sumAll(n-1) + n;
}
}
console.log(sumAll(3));

Perhaps you will enjoy a repeatable technique that can guide you through designing your recursive function. Let's solve sumAll using inductive reasoning -
If n is zero, return the empty sum, zero
(inductive) n is negative or positive. If n is negative, return the negative result of the subproblem sumAll(-n)
(inductive) n is positive. Return n plus the result of the subproblem sumAll(n - 1)
function sumAll(n) {
if (n == 0) // 1
return 0
else if (n < 0) // 2
return -sumAll(-n)
else
return n + sumAll(n - 1) // 3
}
console.log(sumAll(-10), sumAll(0), sumAll(10))
// -55 0 55
Here is sumAll written using a switch instead. It behaves identically but maybe you will find the syntax nicer to read -
function sumAll(n) {
switch (true) {
case n == 0: return 0 // 1
case n < 0: return -1 * sumAll(-n) // 2
default: return n + sumAll(n - 1) // 3
}
}
console.log(sumAll(-10), sumAll(0), sumAll(10))
// -55 0 55
Here is sumAll again as a pure, functional expression -
const sumAll = (n = 0) =>
n == 0 // 1
? 0
: n < 0 // 2
? -1 * sumAll(-n)
: n + sumAll(n - 1) // 3
console.log(sumAll(-10), sumAll(0), sumAll(10))
// -55 0 55

Related

Recursive method keeps going, but in the opposite direction. Why?

So I'm trying to familiarize myself with recursion and Javascript. So I wrote a simple method to try it out. I'm pretty new to Javascript syntax so I'm not really sure where I'm going wrong. Here is the method.
export const IsEven = (n) => {
if(n > 1){
n -= 2;
IsEven(n);
}
else{
var bool = NumberToBool(n);
return bool;
}
}
When stepping through, n does reach 0 or 1 and defines it as true or false. However, the method does not stop at the return statement. Instead, it turns around and starts adding 2 to n. I cannot understand how that is even possible, does anyone have an idea on what is going on?
Thanks
You can use mathematical induction to solve the vast majority of recursive problems -
if n is negative, return the result of isEven(-n)
(inductive) n is zero or greater. if n is greater than one, return the result of the recursive sub-problem, isEven(n - 2)
(inductive) n is neither negative nor greater than 1. this means n is zero or one. zero is even, one is odd. return n == 0 gives us the correct result for both.
const isEven = (n) => {
if (n < 0) return isEven(n * -1) // 1. n is negative
else if (n > 1) return isEven(n - 2) // 2. n is 2 or more
else return n == 0 // 3. n is 0 or 1
}
for (let i = -10; i<10; i++)
console.log(i, isEven(i))
Recursion is a functional heritage and so using it with functional style yields the best results. if statements do not evaluate to a value and instead rely on side effects like return to compute the result. Below we use expressions which evaluate to a value and it allows us to skip a lot of the syntactic noise that comes with imperative style. Now isEven reads more like a formula -
const isEven = n =>
n < 0
? isEven(n * -1) // 1. n is negative
: n > 1
? isEven(n - 2) // 2. n is 2 or more
: n == 0 // 3. n is 0 or 1
for (let i = -5; i < 5; i++)
console.log(i, isEven(i))
n
isEven(n)
-5
false
-4
true
-3
false
-2
true
-1
false
0
true
1
false
2
true
3
false
4
true
isEven can be defined using a synergistic counterpart, isOdd, where each can be defined in terms of the other. This technique is called mutual recursion -
const isEven = n =>
n < 0
? isEven(-n)
: n == 0
? true
: isOdd(n - 1)
const isOdd = n =>
n < 0
? isOdd(-n)
: n == 0
? false
: isEven(n - 1)
for (let i = -5; i < 5; i++)
console.log(`i:${i} isEven:${isEven(i)} isOdd:${isOdd(i)}`)
n
isEven(n)
isOdd(n)
-5
false
true
-4
true
false
-3
false
true
-2
true
false
-1
false
true
0
true
false
1
false
true
2
true
false
3
false
true
4
true
false

Recursion counter doesn't work in codewars kata

Currently trying to complete the persistent bugger kata in code wars.
I need to return the number of times the input has to be multiplied until it is reduced to a single number (full task instructions below).
Everything appears to work apart from the count. when I console log, the number of times it logs and runs is correct, but instead of incrementing such as 1,2,3 it will be something like 2,2,4.
So instead of returning 3, it returns 4.
I try to not ask for help with katas, but this time I am completely at a loss as to why the count is firstly skipping numbers and also not incrementing.
Task:
Write a function, persistence, that takes in a positive parameter num and returns its multiplicative persistence, which is the number of times you must multiply the digits in num until you reach a single digit.
For example:
persistence(39) === 3 // because 3*9 = 27, 2*7 = 14, 1*4=4
// and 4 has only one digit
persistence(999) === 4 // because 9*9*9 = 729, 7*2*9 = 126,
// 1*2*6 = 12, and finally 1*2 = 2
persistence(4) === 0 // because 4 is already a one-digit number
My function:
function persistence(num) {
//console.log('here', num)
if(num < 10) return 0;
if(num === 25) return 2
let spl = num.toString().split('');
let result = 1;
let count = 1;
spl.forEach((s) => {
let int = parseInt(s)
result *= int;
//count++;
})
//console.log(result)
if(result > 9) {
persistence(result)
count++;
}
// console.log('count-->', count)
return count;
}
A sub issue is that the input 25 always returns a count 1 less than it should. My fix is poor I know, again any advice would be much appreciated.
Spoiler alert: this contains a solution. If you don't want that, stop before the end.
You don't really want to work with count, since as people point out, it's a local variable. You also don't work too hard to special case the result if it's a single digit. Let the recursion handle it.
Thus:
function persistence(num) {
//console.log('here', num)
if(num < 10) return 0;
//still here, must be 2 or more digits
let spl = num.toString().split('');
let result = 1;
spl.forEach((s) => {
let int = parseInt(s)
result *= int;
})
//console.log(result)
return 1 + persistence(result)
}
As you already have a complete solution posted here with fixes to your implementation, I will offer what I think is a simpler version. If we had a function to create the digit product for us, then persistence could be this simple recursion:
const persistence = (n) =>
n < 10 ? 0 : 1 + persistence (digProduct (n))
You already have code for the digit product, and while it's fine, a mathematical approach, rather than a string-base one, is somewhat cleaner. We could write it -- also recursively -- like
const digProduct = (n) =>
n < 10 ? n : (n % 10) * digProduct (Math .floor (n / 10))
or instead we might choose (n / 10) | 0 in place of the floor call. Either is reasonable.
Putting it together, we have:
const digProduct = (n) =>
n < 10 ? n : (n % 10) * digProduct ((n / 10) | 0)
const persistence = (n) =>
n < 10 ? 0 : 1 + persistence (digProduct (n))
const tests = [39, 999, 4, 25]
tests.forEach (n => console.log (`${n} --> ${persistence(n)}`))

Sum of even numbers from 1-100 using recursive function in Javascript

I want to sum even numbers from 1-100 using javascript recursive function, but the output just show me 0 for odd numbers and the number itself for odd numbers
function evenSum(n) {
if (n%2 === 1) {
return 0;
}
else if (n === 100) {
return 100;
}
return n + evenSum(n+1);
}
if (n%2 === 1) {
return 0;
}
That will stop the recursive chain at every second number. For every odd number it will stop directly (and return 0) for every even number it will stop at the second position. Instead, you just want the recursion to continue with the next chain:
if (n%2 === 1) {
return evenSum(n + 1);
}
Actually you can simplify (and speed up the code) if you just go to every second position:
function evenSum(n){
// Stop at 100
if(n >= 100) return 100;
// If it starts at an odd position, go on with the next even
if(n % 2 === 1) return evenSum(n + 1);
// Usually just take every second step:
return n + evenSum(n + 2);
}
That can be shortified to:
const evenSum = n => n >= 100 ? 100 : n % 2 ? evenSum(n + 1) : n + evenSum(n + 2);
You could use a recursion function which count down the values until you reach zero.
The exit condition is a check if the number is smaller or equal to zero, then return the sum otherwise decrement uneven value by one and even value by two and call the function again with the value and temporary sum.
function evenSum(n, s = 0) {
if (n <= 0) {
return s;
}
return evenSum(n - (n % 2 ? 1 : 2), s + n); // tail recursion
}
console.log(evenSum(100));
function evenSum(n) {
if (n <= 1)
return 0;
else
{
if(n%2 === 1)
return evenSum(n - 1);
else
return n + evenSum(n - 1);
}
}
Something like that (works for all numbers, not just 100):
function evenSum(n) {
if (n == 0) return 0; // recursive function needs to stop somewhere
var sum = evenSum(n - 1); // recursive call
if (n % 2 == 0) sum += n; // add current n if it's even
return sum; // return result
}
console.log(evenSum(100));
recursive sum of even number
one line condition
function addOddToN(n) {
return (n <= 2) ? 2 : (n%2 === 0) ? n + addOddToN(n - 1) : addOddToN(n - 1);
}
console.log( addOddToN(100) ); // 2550
console.log( addOddToN(5) ); // 6
console.log( addOddToN(4) ); // 6
console.log( addOddToN(10) ); // 30

What is the best way to determine if a given number is a power of two?

Is there a more effective way to return true if n is a power of two or false if not?
function isPowerOfTwo(n) {
return Math.pow(2, Math.round(Math.log(n) / Math.log(2)));
}
You can actually use ECMAScript5 Math.log:
function powerOfTwo(x) {
return (Math.log(x)/Math.log(2)) % 1 === 0;
}
Remember, in math, to get a logarithm with an arbitrary base, you can just divide log10 of the operand (x in this case) by log10 of the base. And then to see if the number is a regular integer (and not a floating point), just check if the remainder is 0 by using the modulus % operator.
In ECMAScript6 you can do something like this:
function powerOfTwo(x) {
return Math.log2(x) % 1 === 0;
}
See the MDN docs for Math.log2.
Source: Bit twiddling Hacks,
function powerOf2(v) {
return v && !(v & (v - 1));
}
You just bitwise AND the previous number with the current number. If the result is falsy, then it is a power of 2.
The explanation is in this answer.
Note:
This will not be 100% true for programming, mathematical, [also read 'interviewing']. Some edge cases not handled by this are decimals (0.1, 0.2, 0.8…) or zero values (0, 0.0, …)
Using bitwise operators, this is by far the best way in terms of efficiency and cleanliness of your code:
function PowerofTwo(n){
return ((x != 0) && !(x & (x - 1)));
}
what it does is checks the bits that make up the number, i.e. 8 looks like this:
1 0 0 0
x-1 or 7 in this case looks like this
0 1 1 1
when the bitwise operator & is used it invokes an && on each bit of the number (thus 1 & 1 = 1, 1 & 0 = 0, 0 & 1 = 0, 0 & 0 = 1):
1 0 0 0
-0 1 1 1
=========
0 0 0 0
since the number turns into an exact 0 (or false when evaluted as a boolean) using the ! flag will return the correct answer
if you were to do this with a number like 7 it would look like this:
0 1 1 1
-0 1 1 0
=========
1 1 1 0
returning a number greater than zero causing the ! flag to take over and give the correct answer.
A number is a power of 2 if and only if log base 2 of that number is whole. The function below computes whether or not that is true:
function powerOfTwo(n){
// Compute log base 2 of n using a quotient of natural logs
var log_n = Math.log(n)/Math.log(2);
// Round off any decimal component
var log_n_floor = Math.floor(log_n);
// The function returns true if and only if log_n is a whole number
return log_n - log_n_floor == 0;
}
Making use of ES6's Math.clz32(n) to count leading zeros of a 32-bit integer from 1 to 2³² - 1:
function isPowerOf2(n) {
return Math.clz32(n) < Math.clz32(n - 1);
}
/**
* #param {number} n
* #return {boolean}
*/
const isPowerOfTwo = function(n) {
if(n == 0) return false;
while(n % 2 == 0){
n = n/2
}
return n === 1
};
function PowerOfTwo(n){
// Exercise for reader: confirm that n is an integer
return (n !== 0) && (n & (n - 1)) === 0;
}
console.log(PowerOfTwo(3))
console.log(PowerOfTwo(4))
This is for a specific online course that requires an answer in a specific way.
Without using libraries and other methods just loops and .push.
you need to create an inner loop using while
it should start with 1
keep multiplying it with 2 until i,j,k or whatever is greater than the current number(array) so it will have to do 2 4 6 8 10 12 14 16 18 until it is greater than the number
then it will go to the outer loop then repeat again until
const numbers = [5, 3, 9, 30];
const smallestPowerOfTwo = arr => {
let results = new Array;
// The 'outer' for loop -
for (let i = 0; i < arr.length; i++) {
number = arr[i];
// The 'inner' while loop
j = 1;
while (j < number) { //starting from 1 then multiplied by 2 then by 2 again untill it is more than the number
j = j * 2;
}
results.push(j);
}
return results
}
console.log(smallestPowerOfTwo(numbers))

Big Integers in Memoized Recursive Fibonacci (Y)

I've written a version of Y that automatically caches old values in a closure using memoization.
var Y = function (f, cache) {
cache = cache || {};
return function (x) {
if (x in cache) return cache[x];
var result = f(function (n) {
return Y(f, cache)(n);
})(x);
return cache[x] = result;
};
};
Now, when almostFibonacci (defined below) is passed into the above function, it returns the value of a large Fibonacci number comfortably.
var almostFibonacci = function (f) {
return function (n) {
return n === '0' || n === '1' ? n : f(n - 1) + f(n - 2);
};
};
However, after a certain value (Number.MAX_SAFE_INTEGER), integers in JavaScript (owing to their IEEE-754 double precision format) are not accurate. So, considering the fact that the only mathematical operations in the Fibonacci function above are addition and subtraction and since operators cannot be overloaded in JavaScript, I wrote naïve implementations of the sum and difference functions (that both use strings to support big integers) which are as follows.
String.prototype.reverse = function () {
return this.split('').reverse().join('');
};
var difference = function (first, second) {
first = first.reverse();
second = second.reverse();
var firstDigit,
secondDigit,
differenceDigits = [],
differenceDigit,
carry = 0,
index = 0;
while (index < first.length || index < second.length || carry !== 0) {
firstDigit = index < first.length ? parseInt(first[index], 10) : 0;
secondDigit = index < second.length ? parseInt(second[index], 10) : 0;
differenceDigit = firstDigit - secondDigit - carry;
differenceDigits.push((differenceDigit + (differenceDigit < 0 ? 10 : 0)).toString());
carry = differenceDigit < 0 ? 1 : 0;
index++;
}
differenceDigits.reverse();
while (differenceDigits[0] === '0') differenceDigits.shift();
return differenceDigits.join('');
};
var sum = function (first, second) {
first = first.reverse();
second = second.reverse();
var firstDigit,
secondDigit,
sumDigits = [],
sumDigit,
carry = 0,
index = 0;
while (index < first.length || index < second.length || carry !== 0) {
firstDigit = index < first.length ? parseInt(first[index], 10) : 0;
secondDigit = index < second.length ? parseInt(second[index], 10) : 0;
sumDigit = firstDigit + secondDigit + carry;
sumDigits.push((sumDigit % 10).toString());
carry = sumDigit > 9 ? 1 : 0;
index++;
}
sumDigits.reverse();
while (sumDigits[0] === '0') sumDigits.shift();
return sumDigits.join('');
};
Now, by themselves, both these functions work perfectly.1
I have now updated the almostFibonacci function to as follows to use the sum function instead of + and the difference function instead of the - operator.
var almostFibonacci = function (f) {
return function (n) {
return n === '0' || n === '1' ? n : sum(f(difference(n, '1')), f(difference(n, '2')));
};
};
As you may have guessed, this does work. It crashes the fiddle in case of even a small number like 10.
Question: What could be wrong? All the functions here work perfectly individually. But in tandem, they seem to fail. Can anyone here help me debug this particularly complex scenario?
1Except an edge case for the difference function. It requires the first argument to be larger than the second.
Now, by themselves, both these functions work perfectly - Except an edge case for the difference function. It requires the first argument to be larger than the second.
And that's the problem. In your fibonacci algorithm you're at some point calculating difference("2", "2"), which needs to yield "0" to work. It does however return the empty string "", which is not tested against as your guard condition for the recursion. When in the next step computing difference("", "1"), the function will fall into an infinite loop.
Solutions:
Fix that edge case (you still won't need to cope with negative numbers)
Don't use strings for the ordinal number, but only for the fibonacci number itself. You hardly will try the compute the (253+1)th fibonacci number, will you? I would assume this to be a significant speed improvement as well.
var fibonacci = Y(function(fib) {
return function(n) {
if (n == 0) return "0";
if (n == 1) return "1";
return sum(fib(n-1), fib(n-2));
};
});
Here is how I solved the problem at hand.
Changes:
I removed the while (differenceDigits[0] === '0') differenceDigits.shift(); statement. Even though this outputs differences without truncated leading zeros, it outputs a '0' in case of an edge case like difference('2', '2').
I edited the return statement in the almostFibonacci function to return n == 0 || n == 1 ? n : sum(f(difference(n, '1')), f(difference(n, '2')));. Notice that I'm checking for 0 and not '0' with a non strict equality operator.1
1The reason I'm doing n == 0 as opposed to n === '0' is because in JavaScript, '00000' == 0 but '00000' !== '0' and in my new updated difference function, without truncated leading zeros, I can't guarantee the number of zeros for a zero output. Well, actually I can. There would be as many zeros as the length of n.
100th Fibonacci - JSFiddle

Categories

Resources