Use Recursion to Sum Digits until there is nothing left to sum - javascript

Question
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 more than one digit, continue reducing in this way until a single-digit number is produced. This is only applicable to the natural numbers.
My Code
function digital_root(n) {
let a = n.toString();
let ai = a.split('');
let bi = ai.map((item)=>{
return parseInt(item);
})
let newArr = [];
for(let i = 0; i < bi.length; i++){
let c = bi[i];
newArr.push(c);
}
let d = newArr.reduce((total, item)=>{
return total + item;
}, 0);
function recursive(d){
if(d < 10){
return d
}
a = d.toString();
ai = a.split('');
bi = ai.map((item)=>{
return parseInt(item);
});
newArr = [];
for(let i = 0; i < bi.length; i++){
let c = bi[i];
newArr.push(c);
}
d = newArr.reduce((total, item)=>{
return total + item;
}, 0);
return recursive(d);
}
return d;
}
console.log(digital_root(123));
console.log(digital_root(111));
console.log(digital_root(51024));
My Problem
For some reason the code doesn't seem to recognise that I need to run the operation again if d >= 9.
How can I resolve the problem with the code that I have already done?
Also out of interest, how would you approach it, my answer seems quite convoluted!

Let's put in some comments to see what is going on.
function digital_root(n) {
// convert multiple digit number to String
let a = n.toString();
// split the String into an array of single digit Strings
let ai = a.split('');
// convert String array into int array
let bi = ai.map((item)=>{
return parseInt(item);
})
// it looks like you are just copying the array here,
//I don't think there is a need for that
// let newArr = [];
// for(let i = 0; i < bi.length; i++){
// let c = bi[i];
// newArr.push(c);
// }
// reduce the int array to the sum of its digits
let d = bi.reduce((total, item)=>{
return total + item;
}, 0);
// That should be it, now just print it or recurse it
if (d < 10) {
return d;
}
// here is how you recurse, call the method from within the method
return digital_root(d);
// I'm not sure what you are doing here, you are repeating code
// this is not how recursion works
// function recursive(d){
// if(d < 10){
// return d
// }
// a = d.toString();
// ai = a.split('');
// bi = ai.map((item)=>{
// return parseInt(item);
// });
// newArr = [];
// for(let i = 0; i < bi.length; i++){
// let c = bi[i];
// newArr.push(c);
// }
// d = newArr.reduce((total, item)=>{
// return total + item;
// }, 0);
// return recursive(d);
// }
// return d;
}
console.log(digital_root(123));
console.log(digital_root(111));
console.log(digital_root(51024));

you never call recursive function you made, replace return d to return recursive(d);
How I would do this:
function digital_root(n){
return n < 10 ? n : digital_root(String(n).split('').reduce((acc,val) => acc+(val|0),0));
}

In addition to what Photon said, here's a simpler solution
function sum(n) {
if (n <= 9) {
return n;
} else {
return sum((n % 10) + sum(n / 10));
}
}
>>> sum(156)
... 3
>>> sum(9999)
... 9
>>> sum(10)
... 1

Related

Character with longest consecutive repetition

i think i have wirtten the correct code for the problem only one thing and it that i return the first longest sequence how can i alter that to return the last maximum sequence?
an example from codewars editor :
for input '00000000000000111111111111111112222222222222223333333333333344444444444445555555555555666666666666777777777777888888888888888999999999999999999aaaaaaaaabbbbbbbbbbbbbbbbcccccccccccccccccccdddddddddddddddddddeeeeeeeeeeeeeeefffffffffffffggggggggggggggghhhhhhhhhhhhhiiiiiiiiiijjjjjjjjjjjjjjkkkkkkkkkkkkllllllllllmmmmmmmmmmnnnnnnnnnnnnnnoooooooooooopppppppppppppppppqqqqqqqqqqqqrrrrrrrrrrrrrrrrrrrssssssssssttttttttttttuuuuuuvvvvvvvvvvvvvvvvvwwwwwwwwwwwwwwwwxxxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyzzzzzzzzzzzzzz'
Expected: ['c', 19], instead got: ['0', 19]
here is my code:
function longestRepetition(s) {
var count = 0;
var temp = s.charAt(0);
var arr = [];
for (var i = 0; i < s.length; i++) {
if (temp === s.charAt(i)) {
count++
temp = s.charAt(i)
}
else {
temp = s.charAt(i);
arr.push(count)
count = 1;
}
if(i==s.length-1)
arr.push(count);
}
if(arr.length>0)
{
var Max=arr[0]
for(var i=0;i<arr.length;i++)
{
if(Max<=arr[i])
Max=arr[i];
}
}
else var Max=0;
var mindex=arr.indexOf(Max);
return [s.charAt(mindex),Max]
}
I think this would be easier with a regular expression. Match any character, then backreference that character as many times as you can.
Then, you'll have an array of all the sequential sequences, eg ['000', 'aaaaa']. Map each string to its length and pass into Math.max, and you'll know how long the longest sequence is.
Lastly, filter the sequences by those which have that much length, and return the last item in the filtered array:
function longestRepetition(s) {
const repeatedChars = s.match(/(.)\1*/g);
const longestLength = Math.max(...repeatedChars.map(str => str.length));
const longestChars = repeatedChars.filter(str => str.length === longestLength);
return [longestChars.pop(), longestLength];
}
console.log(longestRepetition('00000000000000111111111111111112222222222222223333333333333344444444444445555555555555666666666666777777777777888888888888888999999999999999999aaaaaaaaabbbbbbbbbbbbbbbbcccccccccccccccccccdddddddddddddddddddeeeeeeeeeeeeeeefffffffffffffggggggggggggggghhhhhhhhhhhhhiiiiiiiiiijjjjjjjjjjjjjjkkkkkkkkkkkkllllllllllmmmmmmmmmmnnnnnnnnnnnnnnoooooooooooopppppppppppppppppqqqqqqqqqqqqrrrrrrrrrrrrrrrrrrrssssssssssttttttttttttuuuuuuvvvvvvvvvvvvvvvvvwwwwwwwwwwwwwwwwxxxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyzzzzzzzzzzzzzz'));
The issue in your code is that minindex is an index in your arr, but that index has nothing to do with s. So s.charAt(minindex) makes no sense. You should maintain for which character you had found the count. For instance you could push in arr both the count and the corresponding character (as a subarray with two values). Then the rest of your code would only need little modification to make it work.
Applying this idea to your code without changing anything else, we get this:
function longestRepetition(s) {
var count = 0;
var temp = s.charAt(0);
var arr = [];
for (var i = 0; i < s.length; i++) {
if (temp === s.charAt(i)) {
count++
temp = s.charAt(i) // Not necessary: was already equal
}
else {
arr.push([temp, count]); // <--- pair, BEFORE changing temp
temp = s.charAt(i);
count = 1;
}
if(i==s.length-1)
arr.push([temp, count]); // <---
}
if(arr.length>0)
{
var Max=arr[0]; // <-- Max is now a pair of char & count
for(var i=0;i<arr.length;i++)
{
if(Max[1]<arr[i][1]) // Comparison changed to just less-than
Max=arr[i];
}
}
else Max=[null, 0]; // Must be a pair here also
return Max; // Just return the pair
}
console.log(longestRepetition('00000000000000111111111111111112222222222222223333333333333344444444444445555555555555666666666666777777777777888888888888888999999999999999999aaaaaaaaabbbbbbbbbbbbbbbbcccccccccccccccccccdddddddddddddddddddeeeeeeeeeeeeeeefffffffffffffggggggggggggggghhhhhhhhhhhhhiiiiiiiiiijjjjjjjjjjjjjjkkkkkkkkkkkkllllllllllmmmmmmmmmmnnnnnnnnnnnnnnoooooooooooopppppppppppppppppqqqqqqqqqqqqrrrrrrrrrrrrrrrrrrrssssssssssttttttttttttuuuuuuvvvvvvvvvvvvvvvvvwwwwwwwwwwwwwwwwxxxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyzzzzzzzzzzzzzz'));
But you can do the same with less code:
function longestRepetition(s) {
let result = [null, 0]; // pair of character and count
for (var i = 0; i < s.length; null) {
let start = i++;
while (i < s.length && s[i] === s[start]) i++; // Find end of series
if (i - start > result[1]) result = [s[start], i - start];
}
return result;
}
console.log(longestRepetition('00000000000000111111111111111112222222222222223333333333333344444444444445555555555555666666666666777777777777888888888888888999999999999999999aaaaaaaaabbbbbbbbbbbbbbbbcccccccccccccccccccdddddddddddddddddddeeeeeeeeeeeeeeefffffffffffffggggggggggggggghhhhhhhhhhhhhiiiiiiiiiijjjjjjjjjjjjjjkkkkkkkkkkkkllllllllllmmmmmmmmmmnnnnnnnnnnnnnnoooooooooooopppppppppppppppppqqqqqqqqqqqqrrrrrrrrrrrrrrrrrrrssssssssssttttttttttttuuuuuuvvvvvvvvvvvvvvvvvwwwwwwwwwwwwwwwwxxxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyzzzzzzzzzzzzzz'));
The solution below answers the question with O(n) runtime:
function longestRepetition(s) {
let count = s.length > 0 ? 1 : 0
let char = s.length > 0 ? s[0] : ''
for (let string_i = 0; string_i < s.length - 1; string_i += 1) {
// keep track of current_char
let current_char = s[string_i]
let next_char = s[string_i + 1]
// while the next char is same as current_char
let tracker = 1
while (current_char === next_char) {
// add one to tracker
tracker += 1
string_i += 1
next_char = s[string_i + 1]
}
// if tracker greater than count
if (tracker > count) {
// returned char = current char
// count =tracker
count = tracker;
char = current_char;
}
}
return [char, count]
}
console.log(longestRepetition("bbbaaabaaaa"))//, ["a",4]

Multiplying N positive odd numbers

I'm trying to get the product of N positive odd numbers
function multOdd(n) {
var mult = 1;
var counter=[];
for (var i = 1; i <= 2*n-1; i += 2){
counter.push(i);
}
console.log(counter);
return mult=mult*counter[i];
}
console.log(multOdd(10));
I pushed the numbers into an array and attempted to get the product from them but I can't get it to work.
When you return mult=mult*counter[i] you're only returning the multipication once. It should return mult = 1 * counter[lastElement+2] which will be wrong. In your case, the last element of counter is 19, before exiting for loop i value is i= 19 + 2 = 21. You're returning mult = 1 * 21 = 21.
You can instead return the multipication value by for loop with no need for an array:
function multOdd(n) {
var mult = 1;
for (var i = 1; i <= 2*n-1; i += 2){
mult = mult * i;
}
return mult;
}
If you just want the result for n, use:
function multOdd(n) {
var result = 1;
for (var i = 1; i <= 2*n-1; i += 2){
result = result * i;
}
console.log(result);
return result;
}
console.log(multOdd(4));
If you want an array that has an array indexed by the number of odd numbers up to n you could use:
function multOdd(n) {
let result = 1;
let results = [];
for (let i = 1; i <= 2*n-1; i += 2){
result = result * i;
results[(i+1) / 2] = result;
}
console.log(results);
return results;
}
console.log(multOdd(10));
There are a few ways to get the product of an array of numbers. Here are two easy ones:
Relevant MDN
// Using `Array.prototype.reduce`
[3, 5, 7, 9].reduce((acc, val) => acc * val)
// Using a `for ... of` loop
let product = 1
for (const val of [3, 5, 7, 9]) {
product *= val
}
You could separate out the two steps of your current code into two functions:
const getFirstNOddNums = (n) => {
let oddNums = []
for (let i = 1; i <= 2*n-1; i+=2) {
oddNums.push(i)
}
return oddNums
}
const productOfArray = (arr) => {
return arr.reduce((a, b) => a * b)
}
const N = 5
const firstNOddNums = getFirstNOddNums(N)
console.log(`The first ${N} odd numbers are: ${JSON.stringify(firstNOddNums)}`)
console.log(`The product of the first ${N} odd numbers is: ${productOfArray(firstNOddNums)}`)
let multOdd = (n) => {
let total = 1;
for (let i = 1; i<= 2*n; i+=2){
total *= i;
}
return total;
}
console.log(multOdd(10));
Instead of recursion, We should use the standard mathematical formula for the product of first n positive odd integers which is
Can also be written as (in the form of pi notation)
For this latex image, I used https://codecogs.com/latex/eqneditor.php.
Factorial is
n! = n(n-1)(n-2)(n-3) ... and so on
So we can use Array(n).fill() to get an array of 10 elements and reduce them to get a factorial by
Array(n).fill().reduce((v,_,i) => (i+1) * v || 2)
Then we divide it by 2 to the power n times the n!. Which is what we want. The advantage here is that, this makes your solution, a one liner
let n = 10
let answer = Array(2*n).fill().reduce((v,_,i) => (i+1) * v || 2) / (Math.pow(2,n) * Array(n).fill().reduce((v,_,i) => (i+1) * v || 2))
console.log(answer)

How to shuffle a number following a sequence (not random)

I need to build a function that returns a given number shuffled writing one digit from the front of the number and the following taken from the back, then the 3rd digit from the front of the number and the 4th from the back and so on.
Example:
const initialNumber = 123456 should return
const finalNumber = 162534
or
const initialNumber2 = 104 should return
const finalNumber2 = 140
Also, the number should be between the values of 0 and 100.000.000.
How to do it? Should I first transform the number into an array first of all using the split() method and then using a for loop?
You can do it with splitting the input into array and reduce:
const shuffle = input => input.toString().split('').reduce((acc, item, index, data) => {
const arr = (index % 2 ? data.slice().reverse() : data);
return acc.concat(arr[Math.floor(index / 2)]);
}, []).join('');
console.log(shuffle(104)); // 140
console.log(shuffle(123456)); // 162534
console.log(shuffle(1234567)); // 1726354
A bit reduced code:
const shuffle = input => input.toString().split('').reduce((acc, item, index, data) =>
acc.concat((index % 2 ? data.slice().reverse() : data)[Math.floor(index / 2)]), []
).join('');
I would prefer converting the number to a string, then using that string in a for loop.
function shuffle(num) {
var str = num.toString();
var result = "";
if(!isNaN(num) && num >= 0 && num <= 100000000) {
for(var i = 0; i < str.length; i++) {
if(i % 2 == 0) {
result += str[Math.floor(i / 2)];
} else {
result += str[str.length - Math.floor(i / 2 + 1)];
}
}
}
return result;
}
console.log(shuffle(123456)); // 162534
console.log(shuffle(1234567)); // 1726354
console.log(shuffle(104)); // 140
This may work as a very basic algo.
function shuffleNum(num,i){
var numArr = num.toString().split('');
var front = numArr.splice(0,i);
var back = numArr.pop();
var shuffledArr = front.concat(back,numArr);
return parseFloat(shuffledArr.join(''));
}
// Test
var num = 12345;
for(var i=0;i<num.toString().length;i++){
num = shuffleNum(num);
console.log(num);
}
// Output
// 51234
// 45123
// 34512
// 23451
// 12345
The best way is to use array push function.
function shuffle(a) {
var b = a.toString();
var c = [];
for(let i=0; i<b.length/2; i++) {
c.push(b[i]);
if(i==(Math.ceil(b.length/2)-1) && b.length%2==1) continue;
c.push(b[b.length-i-1]);
}
return c.join("");
}
Java code snippet.
public static int solution(int a) {
int[] arr = Integer.toString(a).chars().map(e->e-'0').toArray();
System.out.println(Arrays.toString(arr));
int[] temp = new int[arr.length];
int j=1;
for(int i = 0; i<arr.length; i++) {
if(i % 2 == 0) {
temp[i] = arr[i/2];
} else {
temp[i] = arr[arr.length - j];
j++;
}
}
System.out.println(Arrays.toString(temp));

How can I get the sum of all odd fibonacci vales in javaScript?

I am working through this Free Code Camp exercise.
Return the sum of all odd Fibonacci numbers up to and including the
passed number if it is a Fibonacci number. The first few numbers of the Fibonacci sequence are 1, 1, 2, 3, 5 and
8, and each subsequent number is the sum of the previous two numbers.
And here is what I have so far...
Any suggestions?
function sumFibs(num) {
var arr, isFibVal, isEvenVal, sum, i = 0, fibonacci = function (num){
var a, b, result, fibArr = [1];
a=0;
b=1;
result=b;
for(var j = 0; j < num; j++){
result = a + b;
a = b;
b = result;
fibArr.push(result);
}
return fibArr;
},
isFib = function (val){
var prev = 0;
var curr = 1;
while(prev<=val){
if(prev == val){
return true;
} else {
return false;
}
curr = prev + curr;
prev = curr - prev;
}
},
isEven = function(someNumber){
return (someNumber % 2 === 0) ? true : false;
};
function sumArray(array) {
for (
var
index = 0, // The iterator
length = array.length, // Cache the array length
sum = 0; // The total amount
index < length; // The "for"-loop condition
sum += array[index++] // Add number on each iteration
);
return sum;
}
arr = fibonacci(num);
isFibVal = isFib(num);
isEvenVal = isEven(num);
if (isFibVal && !isEvenVal){
sum += sumArray(arr);
}
return sum;
}
All I get back is undefined which seems to be weird because i thought this part of my code was pretty cool—using the function values to check vs. in the if statement.
arr = fibonacci(num);
isFibVal = isFib(num);
isEvenVal = isEven(num);
if (isFibVal && !isEvenVal){
sum += sumArray(arr);
}
I won't give you the answer outright since you're going through FCC, but I'll provide you with some hints as to where to look:
See this segment:
for(var j = 0; j < num; j++){
result = a + b;
a = b;
b = result;
fibArr.push(result);
}
And this one:
function sumArray(array) {
for (
var
index = 0, // The iterator
length = array.length, // Cache the array length
sum = 0; // The total amount
index < length; // The "for"-loop condition
sum += array[index++] // Add number on each iteration
);
return sum;
}
Also, you probably don't need this segment at all:
isFibVal = isFib(num);
isEvenVal = isEven(num);
if (isFibVal && !isEvenVal){
sum += sumArray(arr);
Good luck. As someone who has finished a good chunk of the curriculum, I can say that Free Code Camp is the real deal.
You're pretty close and the other answer is good for pushing you in the right direction, I'll post a different way that does this using native JS functions:
Example of the code below in JSBin
function fibs(n) {
var f = [0, 1];
var extraNumber = 0;
for (var i = 0; i < n; i++) {
f.push(f[f.length - 1] + f[f.length - 2]);
}
// lets check if the passed in number is a fib:
if (f.indexOf(n) > -1) {
extraNumber = n;
}
console.log(f); // just to check we can cut all the logs later...
var filtered = f.filter(function(num) {
// filter out the even numbers
return num % 2 === 1;
});
console.log(filtered);
var sum = filtered.reduce(function(a, b) {
// add up whats left
return a + b;
});
console.log(sum);
return sum + extraNumber;
}
heres my solution, and i find it to be pretty readable:
function sumOddFibs(num) {
// initialize with 2 because
// fib sequence starts with 1 and 1
var sum = 2;
var prev = 1;
var curr = 1;
var next = 2;
while (next <= num) {
prev = curr;
curr = next;
next = prev + curr;
if (curr % 2 !== 0) {
sum += curr;
}
}
return sum;
}
You could start by defining variables for the previous number, current number, and total Fibonacci
To check for odd numbers, you could use an if statement and use %:
if (currNum % 2 !== 0){ }
If current number is odd, then you add it to the total
fibTotal += currNumber;
To determine the next Fibonacci number you, you will need to add the previous and current number:
var nextNumber = prevNumber + currNumber;
You will need to update the previous number to the current one
prevNumber = currNumber;
Set the current number to the next Fibonacci number in the sequence
currNumber = nextNumber;
Hope this helps.

Trying to square every digit of a number, but my algorithm is not working?

I'm trying to square every digit of a number;
for example:
123 should return 149
983 --> 81649 and so on
I messed it up somewhere in the following Javascript code and I'm looking for some guidance.
function splitNumber(num){
var arr = [];
while(num>0){
var c = num%10;
arr[arr.length]=c;
num=num/10;}
return arr;
}
function squareArrToNumber(arr){
var c = 0;
for(var i=arr.length-1;i>=0;i--){
arr[i]=arr[i]^2;
if(arr[i]^2>10)
c = c*100+arr[i];
else
c = c*10+arr[i];
}
return c;
}
function squareDigits(num){
squareArrToNumber(splitNumber(num));
}
Try out this code
function numToSqr(num){
var i, sqr=[],n;
num = num.toString();
for(i=0;i<num.length;i++){
n = Number(num[i]);
sqr.push(n*n);
}
return Number(sqr.join(""));
}
There are multiple things wrong with your code, starting with an overcomplication to split a string of numbers into its consituant characters just use .splt(""):
var str = "123";
var arr = str.split("");
for(var i = 0;i<arr.length;i++)
alert(arr[i]);
Next, the code num ^ 2 does not square a number. To do a square, simply multiply a number by itself (num * num)
This leaves us with a rather simple solution
function splitNumber(num){
return num.split("");
}
function joinArray(arr){
return arr.join("");
}
function squareArrToNumber(arr){
var newArr = [];
for(var i=0;i<arr.length;i++){
newArr.push(arr[i] * arr[i]);
}
return joinArray(newArr);
}
function squareDigits(num){
return squareArrToNumber(splitNumber(num));
}
alert(squareDigits("123"));
alert(squareDigits("983"));
Here is how I would do such a thing:
var num = 123;
var numArray = num.toString().split("");
var result = "";
for(var i = 0; i < numArray.length; i++){
result += parseInt(numArray[i]) * parseInt(numArray[i]);
}
function squareNum(number) {
var array = [];
// Split number into an array of numbers that make it up
array = String(number).split('');
for (let i = 0; i < array.length; i++) {
// Take each number in that array and square it (in place)
// Also can be done with forEach depending on what es version you're targetting
array[i] = Math.pow(array[i], 2);
}
// combine and return the elements of the array
return Number(array.join(''));
}
squareNum(123);
squareNum(983);
try this example
function squareDigits(n) {
return +(n.toString().split('').map(val => val * val).join(''));
}
console.log(squareDigits(4444));
here + sign is convert the string into an integer.
if(arr[i]^2>10)
should be
if(arr[i]>10)
And, as #Luaan noted, it should be
arr[i] *= arr[i]

Categories