I'm learning the basics of JavaScript and am trying to write a recursive function to add together a group of integers. For example, the function argument would be 1234 and the result should be 10. Here's what I have so far...
function sumDigits(numbersStr) {
var numToString = numbersStr.toString()
var numArr = numToString.split('').map(Number);
var sum = 0;
// base case
if (numArr.length === 0) {
return sum
}
// recursive case
else {
var popped = numArr.pop();
sum+=popped;
return sumDigits(numArr);
}
}
But I get an infinite loop whenever I run this (my tab crashes). If I'm popping the last element of an array, adding it to the sum variable, then calling the function again on the shortened array, then why do I get an infinite loop? Many thanks!
The problem in your code is that sumDigits expects to get a number, but in the recursion you pass an array of numbers to it.
You could use a string or number as argument of the function and convert the value to a string.
Then check the length and return zero if the length is zero (usualy the exit condition).
If not return the value of the fist character and add the result of calling the function with a sliced string from index one.
Basically a recurisve function have two parts.
The exit condition with an exit value. This depends on the purpose of the recursive function. It is usually a neutral value, like zero for addition, or 1 for multiplication.
The actuall value plue a arithmetic operation and the call of the function again with a reduced string/array or numerical value.
function sumDigits(num) {
num = num.toString();
return num.length === 0
? 0
: +num[0] + sumDigits(num.slice(1));
}
console.log(sumDigits(1234));
Another approach would be the use of tail recursion, which does not extend the stack for each calling function, because the function ends with the call without keeping a temporary value liek in above function, the actual numerical value +num[0] and the waiting for execution of the adition.
In this case, you could store the intermediate result along with the calling of the function.
function sumDigits(num, sum) { // num is expected to be a string
sum = sum || 0;
if (num.length === 0) {
return sum;
}
return sumDigits(num.slice(1), sum + +num[0]);
}
console.log(sumDigits('1234'));
function digitCount(num) {
let val1 = num % 10
let rem = Math.floor(num / 10)
return val1 + (rem != 0 ? digitCount(rem) : 0)
}
console.log(digitCount(87))
The problem is that your function takes a number as it's argument, but when you use it recursively, you're giving it an array back. I would recommend pulling the recursive part into its own helper function like so:
function sumDigits(num) {
var numStr = num.toString()
var numArr = numStr.split('').map(Number);
function sumHelper(arr) {
// Base case:
if (arr.length === 1) {
return arr[0];
}
// Otherwise recurse (return last number plus the sum
// of the remainder):
return arr.pop() + sumHelper(arr);
}
// Then use that recursive helper:
return sumHelper(numArr);
}
console.log(sumDigits(1234))
Your function expects a string, but on the recursive call, you pass it an array.
Additionally, you've got a call to .map that isn't needed because you can convert the strings in the .split array to numbers simply by prepending a + to them.
Is there any reason you just don't use Array.reduce?
function sumDigits(stringOfNums) {
// Split the string into an array of strings. Reduce the array to the sum by
// converting each string to a number.
console.log(stringOfNums.split('').reduce(function(x,y){ return +x + +y}, 0));
}
sumDigits("1234");
Passing an array in the recursive call will guarantee that its .toString() will never be empty because the commas will add more characters than have been removed.
Instead, do it mathematically so you don't need an array or even string conversion.
function sumDigits(num) {
return num ? (num%10) + sumDigits(Math.floor(num/10)) : 0
}
console.log(sumDigits(1234))
This assumes a positive integer is passed. You'll need additional guards if other input could be provided.
There's no need to convert the number to an array. You can get the last digit of a number with number % 10, and remove that digit with Math.floor(number / 10). Then recurse until the number is 0.
function sumDigits(num) {
if (num == 0) {
return 0;
} else {
var last = num % 10;
var rest = Math.floor(num / 10);
return last + sumDigits(rest);
}
}
console.log(sumDigits(1234));
Barmar has a good voice of reason. Converting from number to string then converting back to number again is a bit silly. Plus, if this is a homework assignment, using high-level functions like String.prototype.split probably won't teach you much.
Here's a tail-recursive version Barmar's program written using functional style
base case - the input number n is zero, return the accumulator acc
inductive case - n is not zero; recur with the next n and the next acc
const sumDigits = (n = 0, acc = 0) =>
n === 0
? acc
: sumDigits (n / 10 >> 0, acc + n % 10)
console.log (sumDigits ()) // 0
console.log (sumDigits (1)) // 1
console.log (sumDigits (12)) // 3
console.log (sumDigits (123)) // 6
console.log (sumDigits (1234)) // 10
Related
Problem statement: I'm trying to get string > binary without using the inbuilt method in javascript.
This is a piece of program where a string input (like "ABC") is accepted, then it is translated to an array of equivalent code value ([65,66,67]).
Function binary() will change a number to binary. But I'm unable to join them together to loop through all the contents. Please help. (I'm a noob, please forgive my bad code and bad explanation)
var temp3 = [65,66,67];
var temp2 = [];
var r;
for(i=0;i<temp3.length;i++) {
var r = temp3[i];
temp2.push(binary(r));
}
function binary(r) {
if (r === 0) return;
temp2.unshift(r % 2);
binary(Math.floor(r / 2));
return temp2;
}
console.log(temp2);
I think this is a cleaner version of this function. It should work for any non-negative integers, and would be easy enough to extend to the negatives. If we have a single binary digit (0 or 1) and hence are less than 2, we just return the number converted to a string. Otherwise we call recursively on the floor of half the number (as yours does) and append the final digit.
const binary = (n) =>
n < 2
? String (n)
: binary (Math.floor (n / 2)) + (n % 2)
console.log (binary(22)) //=> '10110'
console.log ([65, 66, 67] .map (binary)) //=> ['1000001', '1000010', '1000011']
In your function you have this code
var r = temp3[i];
I don't see any temp3 variable anywhere in your code above so I'd imagine that could be causing some issues.
Hello I'm trying to understand recursion in JavaScript.
So far I have:
function countVowels(string) {
let vowelCount = 0;
// if we're not at the end of the string,
// and if the character in the string is a vowel
if (string.length - 1 >= 0 && charAt(string.length -1) === "aeiouAEIOU") {
//increase vowel count every time we iterate
countVowels(vowelCount++);
}
return vowelCount;
}
First of all, this is giving me issues because charAt is not defined. How else can I say "the character at the current index" while iterating?
I can't use a for-loop - I have to use recursion.
Second of all, am I using recursion correctly here?
countVowels(vowelCount++);
I'm trying to increase the vowel count every time the function is called.
Thanks for your guidance.
If you're interested, here is a version that does not keep track of the index or count, which might illuminate more about how the recursion can be done.
function countVowels(string) {
if (!string.length) return 0;
return (
"aeiou".includes(string.charAt(0).toLowerCase()) +
countVowels(string.substr(1))
);
}
console.log(countVowels("")); // 0
console.log(countVowels("abcde")); // 2
console.log(countVowels("eee")); // 3
// Note that:
console.log('"hello".substr(1)', "hello".substr(1)) // ello
console.log('"hello".charAt(0)', "hello".charAt(0)) // h
console.log('"aeiou".includes("a")', "aeiou".includes("a")) // true
console.log('"a".includes("aeiou")', "a".includes("aeiou")) // false
Our base case is that the string is empty, so we return 0.
Otherwise, we check if the first character in the string is a vowel (true == 1 and false == 0 in javascript) and sum that with counting the next (smaller by one) string.
You are making two mistakes:
You should have three parameters string , count(count of vowels) and current index i.
You should use includes() instead of comparing character with "aeiouAEIOU"
function countVowels(string,count= 0,i=0) {
if(!string[i]) return count
if("aeiou".includes(string[i].toLowerCase())) count++;
return countVowels(string,count,i+1);
}
console.log(countVowels("abcde")) //2
As asked by OP in comments "Can you please explain why it'sif("aeiou".includes(string[i].toLowerCase())) instead of if(string[i].includes("aeiou".toLowerCase()))"
So first we should know what includes does. includes() checks for string if it includes a certain substring passed to it or not. The string on which the method will be used it will be larger string and the value passed to includes() be smaller one.
Wrong one.
"a".includes('aeiou') //checking if 'aeiou' is present in string "a" //false
Correct one.
"aeiou".includes('a') //checking if 'a' is present in string "aeiou" //true
One possible solution would be:
function countVowels(string, number) {
if (!string) return number;
return countVowels(string.slice(1), 'aeiouAEIOU'.includes(string[0])? number + 1 : number);
}
// tests
console.log('abc --> ' + countVowels('abc', 0));
console.log('noor --> ' + countVowels('noor', 0));
console.log('hi --> ' + countVowels('hi', 0));
console.log('xyz --> ' + countVowels('xyz', 0));
and you should call your function like: countVowels('abc', 0)
Notes about your solution:
you always reset vowelCount inside your function, this usually does not work with recursion.
you defined your function to accept a string, but recall it with an integer in countVowels(vowelCount++); this it will misbehave.
always remember that you have to define your base case first thing in your recursion function, to make sure that you will stop sometime and not generate an infinite loop.
Alternative ES6 solution using regex and slice() method. Regex test() method will return true for vowels and as stated in a previous answer JavaScript considers true + true === 2.
const countVowels = str => {
return !str.length ? 0 : /[aeiou]/i.test(str[0]) + countVowels(str.slice(1));
}
I'm a newbie to Javascript so please bear with me for this basic question,
I'm trying to get my function to add all the individual digits in a string together, and then keep doing this until I'm left with a single digit!
3253611569939992595156
113 // result of the above digits all added together
5 //result of 1+1+3
I've created a while loop, but it only adds the numbers together once, it dosn't repeat until a single digit and I can't work out why!
function rootFunc(n) {
var splite = n.toString().split('').map(x => Number(x)); //converts the number to a string, splits it and then converts the values back to a number
while (splite.length > 1) {
splite = splite.reduce(getSum);
}
return splite;
}
console.log(rootFunc(325361156993999259515));
function getSum(total, num) {
return total + num;
}
You're reducing properly, but what you're not doing is re-splitting. Try breaking this out into separate functions:
function digits(n) {
return n.toString().split('').map(x =>Number(x));
}
Then split each time:
function rootFunc(n) {
var d = digits(n);
while (d.length > 1) {
d = digits(d.reduce(getSum));
}
return d;
}
The problem here is that you return the result after the first splice. You need to have a recursive function. To do this, you can put this before the return :
if(splite > 9) splite = rootFunc(splite);
This way, you check if the result is greater than 10, if not you do the function with the remaining digits
I was looking this over in jsfiddle, and your number isn't being passed to exact precision, so just console logging n as soon as you call rootFunc, you've already lost data. Otherwise, to fix your loop, you need to remap splite to a string before the end of your codeblock since your while statement is checking .length, which needs to be called on a string. Put this piece of code at the end of the block:
splite = splite.toString().split('').map(x =>Number(x));
I am trying to count TRAILING zeros from a recursive manner. Basically I split the final recursive result and then created a var counter that will count all the zeros.
function countingZeros(n) {
if (n < 0) {
// Termination condition to prevent infinite recursion
return;
}
// Base case
if (n === 0) {
return 1;
}
// Recursive case
let final = n * countingZeros(n -1);
let counter = 0;
String(final).split('').forEach(function(item){
item === 0 ? counter++ : counter;
});
return counter;
}
countingZeros(12) // => suppose to output 2 since there are 2 trailing zeros from 479001600 but got 0
countingZeros(6) // => suppose to get 1 since 720 is the final result.
I am expecting to get 2 in return as the counter must return but instead I got 0. Any idea what am I missing on my function? How should I fix it?
I think you're working too hard. First of all, in response to a comment, you don't actually need to calculate the factorial, since all you really need is to count factors of 5 and of 2. And since there are many more factors of 2, your real answer is just counting factors of 5. But each factor of 5 must be a factor of one of {1, 2, 3, ... n}, so we just have to add up the highest powers of five that evenly divide into each of {1, 2, 3, ... n}.
We can do that with some simple recursion:
const fiveFactors = (n, acc = 0) => (n % 5 == 0)
? fiveFactors(n / 5, acc + 1)
: acc
const factZeros = (n, acc = 0) => (n > 0)
? factZeros(n - 1, acc + fiveFactors(n))
: acc
factZeros(1000) //=> 249
Note that both functions are eligible for tail-call optimization.
Also, although this does involve a double recursion, it's not really ill-performant. Four out of five times, the internal recursion stops on the first call, and of the remainder, four out of five stop on the second call, and so on.
You are trying to count the number of zeroes using string functions(i will assume, you forgot to include the factorial method. Correct flow could have been- you first pass the input to a factorial method and pass output from factorial method to countingZeros method). Anyways as stated already in other answer, you don't really need to calculate the factorial product to count the trailing zeroes.
Here a sample to count the number of trailing zeroes in n!
temp = 5;
zeroes = 0;
//counting the sum of multiples of 5,5^2,5^3....present in n!
while(n>=temp){
fives = n/temp;
zeroes = zeroes + fives;
temp = temp*5;
}
printf("%d",zeroes);
Note that each multiple of 5 in the factorial product will contribute 1 to the number of trailing zeros. On top of this, each multiple of 25 will contribute an additional 1 to the number of trailing zeros. Then, each multiple of 125 will contribute another 1 to the number of trailing zeros, and so on.
Here's a great link to understand the concept behind this:
https://brilliant.org/wiki/trailing-number-of-zeros/
I think the title needs some explaining. I wan't to make my program break up a number into smaller bits.
For example, it would break 756 into 700, 50 and 6. 9123 would be 9000, 100, 20 and 3. Is there any way I can do this for any reasonably sized number?
Working Example
Here is a function that can do it:
function breakNumbers(num){
var nums = num.toString().split('');
var len = nums.length;
var answer = nums.map(function(n, i) {
return n + (Array(len - i - 1).fill(0)).join('');
});
return answer.map(Number).filter(function(n) {return n !== 0;});
}
function breakup(number) {
var digits = String(number).split('')
return digits.map(function(digit, i) {
return Number(digit.concat("0".repeat(digits.length - i - 1)))
}).filter(function(n) { return n !== 0 })
}
So first, we want to cast the number to a string, so we pass it into the String primitive like so: String(number)
Thus, calling the split method on the array and passing in an empty string (which tells it to split for every character) results in an array of the digits, i.e. ["7", "5", "6"]
We can leave them as strings for now because it makes the next part a little easier. Using the map function, you can pass a function which should be called on each element in the array. Besides the first argument to this function, there's an optional second argument which is the index of the item in the array. This will turn useful in our case, since where a number is in the array indicates what place it is.
Check it out, the value returned by the function passed to map takes the current number string and concats another string onto it, which is a number of repeated "0"s. That number is determined by looking at the parent array's length and subtracting it from the index of the current item being looped on, minus one. This is because arrays are 0-indexed in JavaScript--if we just subtracted digits.length from the i (index) for the first iteration, the values would be 3 and 0 respectively, so you'd end up with 7000 for the first value if you passed in 756. Note also that in our return statement inside the map function, we wrap it back in a Number primitive to cast it back from a string.
Also, you didn't mention this, but I assume you'd rather not have numbers which equal 0 in your example. By calling filter on the final array before its returned, we can effectively make sure that only items which are not equal to 0 are returned. Thus, if you call breakup(756) you'll recieve [700, 50, 6], but breakup(706) will give you [700, 6] instead.
Instead of using split() to break out digits, I used a regex to tokenize the number string. This way, we can easily handle any trailing decimals by treating a digit followed by a decimal point and any further digits as a single token. This also makes it possible to handle digits as part of a larger string.
function splitNumber( number ) {
var parts = [];
var re = /(\d(?:\.\d*)?)/g;
while(next_part = re.exec(number)) {
// adjust place value
parts.forEach( function(element, index) {
parts[index] = 10 * element;
} );
parts.push( next_part[0] );
}
return parts.map(Number).filter(function(n) {return n !== 0});
}