DEV Community

Cover image for Solving the Digital Root Algorithm using JavaScript
isabel k.
isabel k.

Posted on • Edited on

Solving the Digital Root Algorithm using JavaScript

One of my favorite algorithms is finding the digital root of any given integer. A digital root is a single-digit sum that is reached when you iteratively add up the digits that make up a number.

For example:

666
=> 6 + 6 + 6
=> 18
=> 1 + 8 
=> 9
Enter fullscreen mode Exit fullscreen mode

The key to solving this algorithm is to use an iterative method. The solution has to be smart enough to keep executing as long as the returned sum is higher than a single-digit number.

The approach

  1. If our given integer is greater than 9, iterate through each digit in the number.
  2. Add up each digit.
  3. Assess if the sum is a single-digit number.
  4. If not, go back to Step 1.

Let's break it down

1) Create a variable for the sum. Set it to equal the given integer. If this integer is a single-digit number, we'll return it at the very end without mutating it.

function digitalRoot(number) {
   let sum = number
}
Enter fullscreen mode Exit fullscreen mode

2) Write a conditional statement to execute something on the sum if it's a multi-digit number.

function digitalRoot(number) {
   let sum = number
   if (sum > 9) {
      // execute something here
   }
}
Enter fullscreen mode Exit fullscreen mode

3) If the number is greater than 9, turn it into an array so that we can loop through it. In JavaScript, we have to turn the integer into a string, and then call the split() method on it to achieve this.

function digitalRoot(number) {
   let sum = number
   let arr = []

   if (sum > 9) {
      arr = sum.toString().split("")
      console.log(arr) 
   }
}

digitalRoot(24)
=> ["2", "4"]
Enter fullscreen mode Exit fullscreen mode

4) Now let's iterate through the array and sum its elements. We can use the reduce() method for this. reduce() requires a reducer method to execute on, so let's write the logic for it and pass it into reduce(). Inside the reducer method, convert the values into an integer by wrapping each value in parseInt. Since this method will return a single value, we can reassign it to our sum variable.

function digitalRoot(number) {
   let sum = number
   let arr = []
   let reducer = (a,b) => parseInt(a) + parseInt(b)

   if (sum > 9) {
      arr = sum.toString().split("")
      sum = arr.reduce(reducer)
      console.log(sum) 
   }
}

digitalRoot(24)
=> 6
Enter fullscreen mode Exit fullscreen mode

Et voilà! We've solved the algorithm!
...Just kidding. It totally breaks if we pass in any larger numbers.

digitalRoot(666)
=> 18
Enter fullscreen mode Exit fullscreen mode

So how can we keep executing our function while the sum is a multi-digit number?

5) Instead of a conditional if statement, let's use a while loop. The while loop will run while a condition is true, whereas an if statement will just execute once. Let's also move our console.log statement to the end of the function, outside of the loop, so that it only returns a single value.

function digitalRoot(number) {
   let sum = number
   let arr = []
   let reducer = (a,b) => parseInt(a) + parseInt(b)

   while (sum > 9) {
      arr = sum.toString().split("")
      sum = arr.reduce(reducer)
   }

   console.log(sum) 
}

digitalRoot(666)
=> 9
Enter fullscreen mode Exit fullscreen mode

Conclusion

This is one of my favorite algorithms because it's not the most difficult to solve, but still poses an interesting problem. Sound off in the comments if you have a different way of solving this!

Edits made after publishing

Changed the wording in this article because I originally talked about using a recursive solution, but ended up writing just an iterative one. Thanks for all the comments! ✨

Top comments (14)

Collapse
 
kdraypole profile image
Kobe Raypole

Very cool! I'm a Ruby enthusiast so I tried it out in that.

Your Iterative strategy was great but I think using recursion could help reduce some of the complexity and make for some cleaner code.

def d_root(num)
  return num if num < 10

  d_root(num.to_s.split('').reduce(0) {|acc, digit| acc + digit.to_i}) 
end

Ruby gives us some great helpers for integers so we can simplify this even more.

def d_root(num)
  return num if num < 10

  d_root(num.digits.sum) 
end

Nice and simple!

Collapse
 
khuongduybui profile image
Duy K. Bui

Can I cheat?

function d_root(num) {
  return (num % 9) || 9;
}
Enter fullscreen mode Exit fullscreen mode

:D

Collapse
 
pavi2410 profile image
Pavitra Golchha

I am really curious how do you know this?

Collapse
 
khuongduybui profile image
Duy K. Bui

I learnt it first as a math trick for children in Vietnam: to know if something is divisible by 9, you calculate its digitial root and see if the digital root is divisible by 9 (same goes for 3).

When I grew up, I was curious and tried to prove that mathematically, which is how I ended up with digitalRoot(num) = num % 9 (or 9 if divisible by 9) :D

Collapse
 
terkwood profile image
Felix Terkhorn

mathworld.wolfram.com/DigitalRoot....

Looking good in this corner of the thread!

Collapse
 
keltroth profile image
Django Janny

What about d_root(0) ?

Collapse
 
athul7744 profile image
Athul Anil Kumar

Amazing intuition!

Collapse
 
kushal-niroula profile image
Kushal Niroula

Are we sure this is a recursive approach? I feel like this is an iterative solution as we just run a block until a condition is met. The function is not called multiple times.

function dRoot(num) {
  const parts = num.toString().split("");
  const sum = parts.reduce((aggr,part) => parseInt(part) + parseInt(aggr));
  if(sum > 9) return dRoot(sum);
  return sum;
}

I think this qualifies as recursive. But the iterative approach in the article is much more performant I think. Nice article.

Collapse
 
ph1p profile image
Phil

Thank you! I like those tiny little programming "snacks" :)


shortest (recursion) solution I could find:

const dr = r => r < 10 ? r : dr([...r+''].reduce((b,c) => +b+(+c)));

dr(129); // 3
Collapse
 
darthbob88 profile image
Raymond Price

Cool demo, but that's not actually recursion, that's just iteration. An actual recursive solution, if you wanted to do that for some strange reason, would look more like

function digitalRoot(number) {
   let arr = number.toString().split("");
   let reducer = (a,b) => parseInt(a) + parseInt(b);
   let sum = arr.reduce(reducer)

   if (sum > 9) {
       return digitalRoot(sum);
   } else {
       return sum;
   }
}

Also, sidenote, this function does break on very large numbers. That's not OP's fault, that's because Javascript can't reasonably represent things like 1234567891234567891234567891 as an integer. digitalRoot("1234567891234567891234567891") works just fine, though

Collapse
 
luigidcapra profile image
Luigi D. Capra • Edited

function F_iRoot(P_sz0){
var sz0 = "" + P_sz0;
var iLen = sz0.length;
var iNum;
var ch;
var iSum = 0;
for (var i=0; i < iLen; i++) {
ch = sz0.charCodeAt(i);
iNum = ch - 48; // '0' = 0x30 = 48
iSum += iNum;
} /* for /
if (iSum > 9) {
iSum = F_iRoot(iSum);
} /
if /
return(iSum);
} /
F_iRoot */

Collapse
 
sylwiavargas profile image
Sylwia Vargas

I love this post! You explain it all so well! Are you planning on creating an algo series?

Collapse
 
gudimba profile image
Austin Imbastari

thank you so much omg

Collapse
 
sabyrcpu profile image
sabyr-cpu

The better solution I think:

function digital_root(n) {
return (n - 1) % 9 + 1;
}