Multiplicative Persistence program in Javascript not working - javascript

I can't get my program to work. The problem is a kata from Codewars:
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.
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
I've gone through answers to similar problems here already. This is my code:
var count = 0;
var product = 1;
function persistence(num) {
if (num.toString().length == 1) {
count+=0;
return count;
}
for (i of num.toString()) {
product *= Number(i);
}
count++;
var newProduct = product;
// reset product to 1 so that line ten does not
// start with the product from the last loop
product = 1;
persistence(newProduct);
}
I can't tell what the problem is. Initially I was getting a maximum call stack exceeded error. I researched that and realized I did this for my base case:
if (num.length == 1) {
count+=0;
return count;
}
instead of
if (num.toString().length == 1) {
count+=0;
return count;
}
My logic seems sound. What could the problem be?

Here's a much better way of solving your problem, complete with comments that I think gives a pretty clear explanation of what's going on.
function persistence(num) {
// Create a new function that you'll use inside your main function
function multiply(n) {
// Multiply the first number by next number in the array
// until the entire array has been iterated over
return n.reduce(function(a,b){return a*b;});
}
// Set the count to 0
var count =0;
// Use a while loop to iterate the same number of times
// as there are digits in num
while (num.toString().length > 1) {
// Splits the num into an array
num= num.toString().split("");
// Runs multiply on our num array and sets num to the returned
// value in preparation of the next loop.
// The multiply function will for 39 run 3 * 9 = 27,
// next iteration we've set num to 27 so multiply will be
// 2 * 7 = 14, then 1 * 4 = 4, and since num 4 now
// has a length <= 1 the loop stops.
num = multiply(num);
// Increase count by 1 each iteration, then run the next
// iteration in the loop with the new value for num being
// set to the result of the first multiplication.
count++;
}
return count; // return the value of count
}
console.log(persistence(39));// === 3 // because 3*9 = 27, 2*7 = 14, 1*4=4
// and 4 has only one digit
console.log(persistence(999));// === 4 // because 9*9*9 = 729, 7*2*9 = 126,
// 1*2*6 = 12, and finally 1*2 = 2
console.log(persistence(4));// === 0 // because 4 is already a one-digit number
https://jsfiddle.net/8xmpnzng/

Use "of" instead of "in". "in" looks for properties. "of" increments an array.
var count = 0;
var product = 1;
function persistence(num) {
if (num.toString().length == 1) {
count+=0;
return count;
}
for (i of num.toString()) {
product *= Number(i);
}
count++;
var newProduct = product;
// reset product to 1 so that line ten does not
// start with the product from the last loop
product = 1;
persistence(newProduct);
}

I'm pretty sure it's this block:
for (i in num.toString()) {
product *= Number(i);
}
That's a for...in loop, which is used to iterate over keys in an object. If you want to multiply each digit of the num string together, you could split the string into an array, and use the reduce method (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce):
//this coerces the number into a string
const numString = num + ''
//this is the function to pass as the first argument into the reduce method
const multiplyAll = (accumulator, currentVal) => accumulator * Number(currentVal)
let product = numString.split('').reduce(multiplyAll, 1)
It's generally best practice to avoid declaring global variables outside of a function's scope, but you can do a cool trick with your recursion where you declare your count as a parameter in your function like so:
function persistence(num, count = 0) {
And then when you call it again with recursion, you simply add 1 like so:
function persistence(product, count + 1) {

Simpler way of Persistence:
let countIteration = 1;
function persistence(num) {
let numStr = num.toString();
if(numStr.toString().length === 1) {
return 0;
}
let numArr = numStr.split("");
let persistRes = numArr.reduce((acc, curr) => acc = curr * acc);
if (persistRes.toString().length !== 1) {
countIteration += 1;
return persistence(persistRes);
}
else {
return countIteration;
}
}
console.log(persistence(39)); // === 3
console.log(persistence(15)); // === 1
console.log(persistence(999));// === 4

Related

Recursive approach to Persistent bugger problem returns undefined

I've been trying to solve the following problem in codewars using recursion:
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 (Input --> Output):
39 --> 3 (because 3*9 = 27, 2*7 = 14, 1*4 = 4 and 4 has only one digit)
999 --> 4 (because 9*9*9 = 729, 7*2*9 = 126, 1*2*6 = 12, and finally 1*2 = 2)
4 --> 0 (because 4 is already a one-digit number)
Here's what I've tried:
var numOfIterations = 0;
function persistence(num) {
//code me
var i;
var digits=[];
var result = 1;
if (num.toString().length==1) {
return numOfIterations;
} else {
numOfIterations++;
digits = Array.from(String(num), Number);
for (i=0;i<digits.size;i++) {
result=result*digits[i];
}
persistence(result);
}
}
But for some reason, instead of returning the number of iterations, it returns undefined. I've been told that I'm not using recursion correctly, but I just can't find the problem.
Other answers have explained what's wrong with your code. I just want to point out a simpler implementation:
const multiplyDigits = (n) =>
n < 10 ? n : (n % 10) * multiplyDigits (n / 10 | 0);
const persistence = (n) =>
n < 10 ? 0 : 1 + persistence (multiplyDigits (n));
[39, 999, 4] .forEach (t => console .log (`${t}:\t${persistence (t)}`));
multiplyDigits does just what it says, recursively multiplying the final digit by the number left when you remove that last digit (Think of | 0 as like Math .floor), and stopping when n is a single digit.
persistence checks to see if we're already a single digit, and if so, returns zero. If not, we add one to the value we get when we recur on the multiple of the digits.
I've been told that I'm not using recursion correctly
You're recursing, but you're not returning the result of that recursion. Imagine for a moment just this structure:
function someFunc() {
if (someCondition) {
return 1;
} else {
anotherFunc();
}
}
If someCondition is false, what does someFunc() return? Nothing. So it's result is undefined.
Regardless of any recursion, at its simplest if you want to return a result from a function then you need to return it:
function persistence(num) {
//...
if (num.toString().length==1) {
//...
} else {
//...
return persistence(result); // <--- here
}
}
As #David wrote in his answer, you were missing the return of the recursive call to itself.
Plus you were using digits.size instead of digits.length.
Anyway consider that one single digit being zero will collpse the game because that's enough to set the result to zero despite how many digits the number is made of.
To deal with the reset of numOfIterations, at first I tried using function.caller to discriminate between recursive call and direct call and set the variable accordingly. Since that method is deprecated as shown here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/caller
I opted for the optional argument iteration that gets set to zero as default, to keep track of that value while it goes down the call stack. This solution still fulfills the fact that the caller doesn't need to know a new interface for the function to work.
//var numOfIterations = 0;
function persistence(num, iteration=0) {
/*
Commented strategy using the function.caller
working but deprecated so I can't recommend anymore
used optional argument iteration instead
//gets the name of the caller scope
let callerName = persistence.caller?.name;
//if it's different from the name of this function
if (callerName !== 'persistence')
//reset the numOfIterations
numOfIterations = 0;
*/
var digits=[];
if (num.toString().length==1){
return iteration;
} else {
var result = 1;
digits = Array.from(String(num), Number);
for (let i=0;i<digits.length;i++) {
result = result * digits[i];
}
return persistence(result, iteration+1);
}
}
console.log( persistence(39) ); //-> 3
console.log( persistence(999 ) ); //-> 4
console.log( persistence(4) ); //-> 0
You can do something like this
const persistenceTailRecursive = (num, iterations = 0) => {
const str = '' + num;
if(str.length === 1){
return iterations;
}
return persistenceTailRecursive(str.split('').reduce((res, a) => res * parseInt(a), 1), iterations + 1)
}
const persistence = (num) => {
const str = '' + num;
if(str.length === 1){
return 0;
}
return 1 + persistence(str.split('').reduce((res, a) => res * parseInt(a), 1))
}
console.log(persistenceTailRecursive(93))
console.log(persistenceTailRecursive(999))
console.log(persistence(93))
console.log(persistence(999))
There are 2 versions
1 tailRecursive call the same method with the exact signature (preventing stackoverflow in some languages like scala)
2 basic the result is calculated at the end

How do I put a calculation inside a for loop with an if statement in between? What is the correct syntax?

With the use of my for loop looping backwards I want to get every other digit, double it and check if that number is bigger than 9. If the number is bigger than 9, I want to subtract nine from it. I want to do this in one function. Maybe use a built in function. This is what I got so far:
const validateCred = array => {
for (let i = array.length -2; i >= 0; i = i -2 ) {
let multiply = array[i] * 2;
if (multiply > 9) {
let minusNine = multiply -9;
}
}
};
Any suggestions would be a big help!
first You need an array to store numbers for iterated array res.
to iterate backwords you must start with array.length - 1 not -2 or you will lost last one.
to iterated over all numbers decrement the i with -1
const validateCred = array => {
const res = [];
for (let i = array.length -1; i >= 0; i = i -1 ) {
let multiply = array[i] * 2;// double it
if (multiply > 9) {//check if that number is bigger than 9
let minusNine = multiply -9;//subtract nine from it
res.push(minusNine);
}else{
res.push(array[i]); //just store as it is.
}
}
return res.reverse()
};
validateCred([10,3,40,9]);// [11, 3, 71, 9]

javascript external called function does not return value [duplicate]

Im solving a codewars problem and im pretty sure i've got it working:
function digital_root(n) {
// ...
n = n.toString();
if (n.length === 1) {
return parseInt(n);
} else {
let count = 0;
for (let i = 0; i < n.length; i++) {
//console.log(parseInt(n[i]))
count += parseInt(n[i]);
}
//console.log(count);
digital_root(count);
}
}
console.log(digital_root(942));
Essentially it's supposed to find a "digital root":
A digital root is the recursive sum of all the digits in a number.
Given n, take the sum of the digits of n. If that value has two
digits, continue reducing in this way until a single-digit number is
produced. This is only applicable to the natural numbers.
So im actually getting the correct answer at the end but for whatever reason on the if statement (which im watching the debugger run and it does enter that statement it will say the return value is the correct value.
But then it jumps out of the if statement and tries to return from the main digital_root function?
Why is this? shouldn't it break out of this when it hits the if statement? Im confused why it attempt to jump out of the if statement and then try to return nothing from digital_root so the return value ends up being undefined?
You're not returning anything inside else. It should be:
return digital_root(count);
^^^^^^^
Why?
digital_root is supposed to return something. If we call it with a one digit number, then the if section is executed, and since we return from that if, everything works fine. But if we provide a number composed of more than one digit then the else section get executed. Now, in the else section we calculate the digital_root of the count but we don't use that value (the value that should be returned). The line above could be split into two lines of code that makes it easy to understand:
var result = digital_root(count); // get the digital root of count (may or may not call digital_root while calculating it, it's not owr concern)
return result; // return the result of that so it can be used from the caller of digital_root
Code review
My remarks is code comments below
// javascript generally uses camelCase for function names
// so this should be digitalRoot, not digital_root
function digital_root(n) {
// variable reassignment is generally frowned upon
// it's somewhat silly to convert a number to a string if you're just going to parse it again
n = n.toString();
if (n.length === 1) {
// you should always specify a radix when using parseInt
return parseInt(n);
} else {
let count = 0;
for (let i = 0; i < n.length; i++) {
//console.log(parseInt(n[i]))
count += parseInt(n[i]);
}
// why are you looping above but then using recursion here?
// missing return keyword below
digital_root(count);
}
}
console.log(digital_root(942));
Simple recursive solution
With some of those things in mind, let's simplify our approach to digitalRoot...
const digitalRoot = n =>
n < 10 ? n : digitalRoot(n % 10 + digitalRoot((n - n % 10) / 10))
console.log(digitalRoot(123)) // => 6
console.log(digitalRoot(1234)) // 10 => 1
console.log(digitalRoot(12345)) // 15 => 6
console.log(digitalRoot(123456)) // 21 => 3
console.log(digitalRoot(99999999999)) // 99 => 18 => 9
Using reduce
A digital root is the recursive sum of all the digits in a number. Given n, take the sum of the digits of n. If that value has two digits, continue reducing in this way until a single-digit number is produced. This is only applicable to the natural numbers.
If you are meant to use an actual reducing function, I'll show you how to do that here. First, we'll make a toDigits function which takes an integer, and returns an Array of its digits. Then, we'll implement digitalRoot by reducing those those digits using an add reducer initialized with the empty sum, 0
// toDigits :: Int -> [Int]
const toDigits = n =>
n === 0 ? [] : [...toDigits((n - n % 10) / 10), n % 10]
// add :: (Number, Number) -> Number
const add = (x,y) => x + y
// digitalRoot :: Int -> Int
const digitalRoot = n =>
n < 10 ? n : digitalRoot(toDigits(n).reduce(add, 0))
console.log(digitalRoot(123)) // => 6
console.log(digitalRoot(1234)) // 10 => 1
console.log(digitalRoot(12345)) // 15 => 6
console.log(digitalRoot(123456)) // 21 => 3
console.log(digitalRoot(99999999999)) // 99 => 18 => 9
its a recursive function the code should be somewhat like this
function digital_root(n) {
// ...
n=n.toString();
if(n.length === 1){
return parseInt(n);
}
else
{
let count = 0;
for(let i = 0; i<n.length;i++)
{
//console.log(parseInt(n[i]))
count+=parseInt(n[i]);
}
//console.log(count);
return digital_root(count);
}
}
you should return the same function instead of just calling it to get the correct call stack

Codewars division Kata using Javascript is producing results that are not divisble by 6

I am trying to solve this Kata from Codewars: https://www.codewars.com/kata/simple-fun-number-258-is-divisible-by-6/train/javascript
The idea is that a number (expressed as a string) with one digit replaced with *, such as "1047*66", will be inserted into a function. You must return an array in which the values are the original number with the * replaced with any digit that will produce a number divisive by 6. So given "1*0", the correct resulting array should be [120, 150, 180].
I have some code that is producing some correct results but erroring for others, and I can't figure out why. Here's the code:
function isDivisibleBy6(s) {
var results = [];
for(i=0;i<10;i++) {
var string = i.toString(); // Convert i to string, ready to be inserted into s
var array = Array.from(s); // Make an array from s
var index = array.indexOf("*"); // Find where * is in the array of s
array[index] = string; // Replace * with the string of i
var number = array.join(""); // Join all indexes of the s array back together. Now we should have
// a single number expressed as a string, with * replaced with i
parseInt(number, 10); // Convert the string to an integer
if((number % 6) == 0) {
results.push(number);
} // If the integer is divisible by 6, add the integer into the results array
}
return(results);
};
This code works with the above example and generally with all smaller numbers. But it is producing errors for larger numbers. For example, when s is "29070521868839*57", the output should be []. However, I am getting ['29070521868839257', '29070521868839557', '29070521868839857']. I can't figure out where this would be going wrong. Is anyone able to help?
The problem is that these numbers are larger than the Number.MAX_SAFE_INTEGER - the point when JavaScript numbers break down in terms of reliability:
var num = 29070521868839257;
console.log(num > Number.MAX_SAFE_INTEGER);
console.log(num % 6);
console.log(num)
The last log shows that the num actually has a different value than what we gave it. This is because 29070521868839257 simply cannot be represented by a JavaScript number, hence you get the closest possible value that can be represented and that's 29070521868839256.
So, after some point in numbers, all mathematical operations become unreliable as the very numbers are imprecise.
What you can do instead is ignore treating this whole as a number - treat it as a string and only apply the principles of divisibility. This makes the task vastly easier.
For a number to be divisible by 6 it has to cover two criteria:
it has to be divisible by 2.
to verify this, you can just get the very smallest digit and check if it's divisible by 2. For example in 29070521868839257 if we take 7, and check 7 % 2, we get 1 which means that it's odd. We don't need to consider the whole number.
it has to be divisible by 3.
to verify this, you can sum each of the digits and see if that sum is divisible by 3. If we sum all the digits in 29070521868839257 we get 2 + 9 + 0 + 7 + 0 + 5 + 2 + 1 + 8 + 6 + 8 + 8 + 3 + 9 + 2 + 5 + 7 = 82 which is not divisible by 3. If in doubt, we can sum the digits again, since the rule can be applied to any number with more than two digits: 8 + 2 = 10 and 1 + 0 = 1. That is still not divisible by 3.
So, if we apply these we can get something like:
function isDivisibleBy6(s) {
return isDivisibleBy2(s) && isDivisibleBy3(s);
};
function isDivisibleBy2(s) {
var lastDigit = Number(s.slice(-1));
return (lastDigit % 2) === 0;
}
function isDivisibleBy3(s) {
var digits = s.split("")
.map(Number);
var sum = digits.reduce(function(a, b) {
return a + b
});
return (sum % 3) === 0;
}
console.log(isDivisibleBy6("29070521868839257"));
console.log(isDivisibleBy6("29070521868839256"));
These can even be recursively defined true to the nature of these rules:
function isDivisibleBy6(s) {
return isDivisibleBy2(s) && isDivisibleBy3(s);
};
function isDivisibleBy2(s) {
if (s.length === 0) {
return false;
}
if (s.length > 1) {
return isDivisibleBy2(s.slice(-1));
}
var lastDigit = Number(s);
return (lastDigit % 2) === 0;
}
function isDivisibleBy3(s) {
if (s.length === 0) {
return false;
}
if (s.length > 1) {
var digits = s.split("")
.map(Number);
var sum = digits.reduce(function(a, b) {
return a + b
});
return isDivisibleBy3(String(sum));
}
var num = Number(s);
return (num % 3) === 0;
}
console.log(isDivisibleBy6("29070521868839257"));
console.log(isDivisibleBy6("29070521868839256"));
This is purely to demonstrate the rules of division and how they can be applied to strings. You have to create numbers that will be divisible by 6 and to do that, you have to replace an asterisk. The easiest way to do it is like you did - generate all possibilities (e.g., 1*0 will be 100, 110, 120, 130, 140, 150, 160, 170, 180, 190) and then filter out whatever is not divisible by 6:
function isDivisibleBy6(s) {
var allDigits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
var allPossibleNumbers = allDigits.map(function(digit) {
return s.replace("*", digit);
});
var numbersDibisibleBySix = allPossibleNumbers.filter(function(s) {
return isDivisibleBy2(s) && isDivisibleBy3(s);
})
return numbersDibisibleBySix;
};
function isDivisibleBy2(s) {
var lastDigit = Number(s.slice(-1));
return (lastDigit % 2) === 0;
}
function isDivisibleBy3(s) {
var digits = s.split("")
.map(Number);
var sum = digits.reduce(function(a, b) {
return a + b
});
return (sum % 3) === 0;
}
console.log(isDivisibleBy6("29070521868839*57"));
console.log(isDivisibleBy6("29070521868839*56"));
As a last note, this can be written more concisely by removing intermediate values and using arrow functions:
function isDivisibleBy6(s) {
return [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
.map(digit => s.replace("*", digit))
.filter(s => isDivisibleBy2(s) && isDivisibleBy3(s));
};
const isDivisibleBy2 = s => Number(s.slice(-1)) % 2 === 0;
const isDivisibleBy3 = s => s.split("")
.map(Number)
.reduce((a, b) => a + b) % 3 === 0
console.log(isDivisibleBy6("29070521868839*57"));
console.log(isDivisibleBy6("29070521868839*56"));
Sum of all digits is divisible by three and the last digit is divisible by two.
An approach:
Get the index of the star.
Get left and right string beside of the star.
Return early if the last digit is not divisible by two.
Take the sum of all digits.
Finally create an array with missing digits:
Start loop from either zero (sum has no rest with three) or take the delta of three and the rest (because you want a number which is divisible by three).
Go while value is smaller then ten.
Increase the value either by 3 or by 6, if the index of the star is the last character.
Take left, value and right part for pushing to the result set.
Return result.
function get6(s) {
var index = s.indexOf('*'),
left = s.slice(0, index),
right = s.slice(index + 1),
result = [],
sum = 0,
i, step;
if (s[s.length - 1] % 2) return [];
for (i = 0; i < s.length; i++) if (i !== index) sum += +s[i];
i = sum % 3 && 3 - sum % 3;
step = s.length - 1 === index ? 6 : 3;
for (; i < 10; i += step) result.push(left + i + right);
return result;
}
console.log(get6("*")); // ["0", "6"]
console.log(get6("10*")); // ["102", "108"]
console.log(get6("1*0")); // ["120", "150", "180"]
console.log(get6("*1")); // []
console.log(get6("1234567890123456789012345678*0")); // ["123456789012345678901234567800","123456789012345678901234567830","123456789012345678901234567860","123456789012345678901234567890"]
.as-console-wrapper { max-height: 100% !important; top: 0; }
The problem is with:
parseInt(number, 10);
You can check and see that when number is large enough, this result converted back to string is not equal to the original value of number, due to the limit on floating point precision.
This challenge can be solved without having to convert the given string to number. Instead use a property of numbers that are multiples of 6. They are multiples of 3 and even. Multiples of 3 have the property that the sum of the digits (in decimal representation) are also multiples of 3.
So start by checking that the last digit is not 1, 3, 5, 7, or 9, because in that case there is no solution.
Otherwise, sum up the digits (ignore the asterisk). Determine which value you still need to add to that sum to get to a multiple of 3. This will be 0, 1 or 2. If the asterisk is not at the far right, produce solutions with this digit, and 3, 6, 9 added to it (until you get double digits).
If the asterisk is at the far right, you can do the same, but you must make sure that you exclude odd digits in that position.
If you are desperate, here is a solution. But I hope you can make it work yourself.
function isDivisibleBy6(s) {
// If last digit is odd, it can never be divisable by 6
if ("13579".includes(s[s.length-1])) return [];
let [left, right] = s.split("*");
// Calculate the sum of the digits (ignore the asterisk)
let sum = 0;
for (let ch of s) sum += +ch || 0;
// What value remains to be added to make the digit-sum a multiple of 3?
sum = (3 - sum%3) % 3;
// When asterisk in last position, then solution digit are 6 apart, otherwise 3
let mod = right.length ? 3 : 6;
if (mod === 6 && sum % 2) sum += 3; // Don't allow odd digit at last position
// Build the solutions, by injecting the found digit values
let result = [];
for (; sum < 10; sum += mod) result.push(left + sum + right);
return result;
}
// Demo
console.log(isDivisibleBy6("1234567890123456789012345678*0"));
BigInt
There is also another way to get around the floating point precision problem: use BigInt instead of floating point. However, BigInt is not supported on CodeWars, at least not in that specific Kata, where the available version of Node goes up to 8.1.3, while BigInt was introduced only in Node 10.
function isDivisibleBy6(s) {
let [left, right] = s.split("*");
let result = [];
for (let i = 0; i < 10; i++) {
let k = BigInt(left + i + right);
if (k % 6n === 0n) result.push(k.toString());
}
return result;
}
// Demo
console.log(isDivisibleBy6("1234567890123456789012345678*0"));
This would anyway feel like "cheating" (if it were accepted), as it's clearly not the purpose of the Kata.
As mentioned, the values you are using are above the maximum integer value and therefore unsafe, please see the docmentation about this over here Number.MAX_SAFE_INTEGER. You can use BigInt(string) to use larger values.
Thanks for all the responses. I have now created successful code!
function isDivisibleBy6(s) {
var results = [];
for(i=0;i<10;i++) {
var string = i.toString();
var array = Array.from(s);
var index = array.indexOf("*");
array[index] = string;
var div2 = 0;
var div3 = 0;
if(parseInt((array[array.length-1]),10) % 2 == 0) {
div2 = 1;
}
var numarray = array.map((x) => parseInt(x));
if(numarray.reduce(function myFunc(acc, value) {return acc+value}) % 3 == 0) {
div3 = 1;
}
if(div2 == 1 && div3 == 1) {
results.push(array.join(""));
}
}
return(results);
};
I know this could be factored down quite a bit by merging the if expressions together, but I like to see things split out so that when I look back over previous solutions my thought process is clearer.
Thanks again for all the help!

Javascript recursive function not returning value?

Im solving a codewars problem and im pretty sure i've got it working:
function digital_root(n) {
// ...
n = n.toString();
if (n.length === 1) {
return parseInt(n);
} else {
let count = 0;
for (let i = 0; i < n.length; i++) {
//console.log(parseInt(n[i]))
count += parseInt(n[i]);
}
//console.log(count);
digital_root(count);
}
}
console.log(digital_root(942));
Essentially it's supposed to find a "digital root":
A digital root is the recursive sum of all the digits in a number.
Given n, take the sum of the digits of n. If that value has two
digits, continue reducing in this way until a single-digit number is
produced. This is only applicable to the natural numbers.
So im actually getting the correct answer at the end but for whatever reason on the if statement (which im watching the debugger run and it does enter that statement it will say the return value is the correct value.
But then it jumps out of the if statement and tries to return from the main digital_root function?
Why is this? shouldn't it break out of this when it hits the if statement? Im confused why it attempt to jump out of the if statement and then try to return nothing from digital_root so the return value ends up being undefined?
You're not returning anything inside else. It should be:
return digital_root(count);
^^^^^^^
Why?
digital_root is supposed to return something. If we call it with a one digit number, then the if section is executed, and since we return from that if, everything works fine. But if we provide a number composed of more than one digit then the else section get executed. Now, in the else section we calculate the digital_root of the count but we don't use that value (the value that should be returned). The line above could be split into two lines of code that makes it easy to understand:
var result = digital_root(count); // get the digital root of count (may or may not call digital_root while calculating it, it's not owr concern)
return result; // return the result of that so it can be used from the caller of digital_root
Code review
My remarks is code comments below
// javascript generally uses camelCase for function names
// so this should be digitalRoot, not digital_root
function digital_root(n) {
// variable reassignment is generally frowned upon
// it's somewhat silly to convert a number to a string if you're just going to parse it again
n = n.toString();
if (n.length === 1) {
// you should always specify a radix when using parseInt
return parseInt(n);
} else {
let count = 0;
for (let i = 0; i < n.length; i++) {
//console.log(parseInt(n[i]))
count += parseInt(n[i]);
}
// why are you looping above but then using recursion here?
// missing return keyword below
digital_root(count);
}
}
console.log(digital_root(942));
Simple recursive solution
With some of those things in mind, let's simplify our approach to digitalRoot...
const digitalRoot = n =>
n < 10 ? n : digitalRoot(n % 10 + digitalRoot((n - n % 10) / 10))
console.log(digitalRoot(123)) // => 6
console.log(digitalRoot(1234)) // 10 => 1
console.log(digitalRoot(12345)) // 15 => 6
console.log(digitalRoot(123456)) // 21 => 3
console.log(digitalRoot(99999999999)) // 99 => 18 => 9
Using reduce
A digital root is the recursive sum of all the digits in a number. Given n, take the sum of the digits of n. If that value has two digits, continue reducing in this way until a single-digit number is produced. This is only applicable to the natural numbers.
If you are meant to use an actual reducing function, I'll show you how to do that here. First, we'll make a toDigits function which takes an integer, and returns an Array of its digits. Then, we'll implement digitalRoot by reducing those those digits using an add reducer initialized with the empty sum, 0
// toDigits :: Int -> [Int]
const toDigits = n =>
n === 0 ? [] : [...toDigits((n - n % 10) / 10), n % 10]
// add :: (Number, Number) -> Number
const add = (x,y) => x + y
// digitalRoot :: Int -> Int
const digitalRoot = n =>
n < 10 ? n : digitalRoot(toDigits(n).reduce(add, 0))
console.log(digitalRoot(123)) // => 6
console.log(digitalRoot(1234)) // 10 => 1
console.log(digitalRoot(12345)) // 15 => 6
console.log(digitalRoot(123456)) // 21 => 3
console.log(digitalRoot(99999999999)) // 99 => 18 => 9
its a recursive function the code should be somewhat like this
function digital_root(n) {
// ...
n=n.toString();
if(n.length === 1){
return parseInt(n);
}
else
{
let count = 0;
for(let i = 0; i<n.length;i++)
{
//console.log(parseInt(n[i]))
count+=parseInt(n[i]);
}
//console.log(count);
return digital_root(count);
}
}
you should return the same function instead of just calling it to get the correct call stack

Categories

Resources