loading...

Daily Challenge #264 - Digital Root

thepracticaldev profile image dev.to staff ・1 min read

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.

Examples

16  -->  1 + 6 = 7
942  -->  9 + 4 + 2 = 15  -->  1 + 5 = 6
132189  -->  1 + 3 + 2 + 1 + 8 + 9 = 24  -->  2 + 4 = 6
493193  -->  4 + 9 + 3 + 1 + 9 + 3 = 29  -->  2 + 9 = 11 --> 1 + 1 = 2

Tests

digital_root(456)
digital_root(16)

Good luck!


This challenge comes from user578387 on CodeWars. Thank you to CodeWars, who has licensed redistribution of this challenge under the 2-Clause BSD License!

Want to propose a challenge idea for a future post? Email yo+challenge@dev.to with your suggestions!

Discussion

pic
Editor guide
Collapse
ayanb profile image
Ayan Banerjee

Property of the digital root is that the result would be n % 9 and n % 9 == 0 it will be 9.

int digitalRoot(int n) {
    if (n == 0) return 0;
    if (n % 9 == 0) return 9;
    return n % 9;
}
Collapse
peter279k profile image
peter279k

Here is the Python code snippets with nest while loop:

def digital_root(n):
    result = 0
    n = str(n)

    index = 0
    while len(n) != 1:
        while index < len(n):
            result += int(n[index])
            index += 1

        index = 0
        n = str(result)
        result = 0

    return int(n)
Collapse
agtoever profile image
agtoever

Python 3 using direct calculation. Defined as function with test cases in the tio link.

digital_root = lambda n: 0 if n == 0 else 1 + (n - 1) % 9

Try it online!

Collapse
rafaacioly profile image
Rafael Acioly

why 1 + (n - 1)?

Collapse
dry profile image
Hayden Mankin

It's important to remember that the % operator happens before +, this solves the edge cases around numbers divisible by 9 without needing extra if statements/ternaries.

For instance,

18 -> 1 + 8 = 9

however,

18 % 9 = 0

which does not fit the problem specification, so instead we do

(18 - 1) % 9 + 1 = 17 % 9 + 1 = 8 + 1 = 9
Collapse
bigj1m profile image
Jim Plourde

I tested it with just n and it works fine.

Collapse
aminnairi profile image
Amin

Haskell

sumDigits :: Int -> Int
sumDigits 0 = 0
sumDigits n = (mod n 10) + sumDigits (div n 10)

digitalRoot :: Int -> Int
digitalRoot n
    | n > 9     = digitalRoot (sumDigits n)
    | otherwise = n
Collapse
bigj1m profile image
Jim Plourde

Here's my solution in Python. Not bad considering I gave it only 5 minutes. I could have gone with reduce and lambda, but it's not really pythonic, not fast and the reading would be terrible. I like the short circuit behavior.

def digital_root(n):
  while True:
    n_list = [int(d) for d in str(n)]
    if len(n_list) == 1:
      return n
    n = sum(n_list)
Collapse
filopd profile image
Priyesh Naik

Python 3 (indent 3 is not reflecting in comment)

ip_val = input("Enter the number?")

if ip_val.isdigit():
while len(ip_val) > 1:
res = 0
for e in ip_val:
res += int(e)
ip_val = str(res)
print(ip_val)

Collapse
johnmilimo profile image
JMW

n % 9 is such an interesting property! But since I had no knowledge of it, I went with a naive solution in KOTLIN which I cracked within a few minutes:

fun digitalRoot(number: Int): Int {
    return if(number < 10) {
        number
    } else {
        val digits = number.toString().split("")
        var sum = 0
        digits.forEach {
            val digit = it.toIntOrNull()
            if(digit != null) { sum += digit}
        }
        digitalRoot(sum)
    }
}
Collapse
willsmart profile image
willsmart

Anytime there's this sort of array summarizing is a good time for reduce
Here's a wee JS implementation of the recursive method (didn't know about the modulus one, pretty neat)

knuckle = n =>
  n<10 ? n : knuckle(
    [... ''+n].reduce(
      (acc, char)=>acc + ~~char,
      0
    )
  )

So, for numbers greater than ten, convert the number to a string (''+n), split the string into its digits ([... ''+n]), and accumulate the sum of those digits ([... ''+n].reduce((acc, char)=>acc + ~~char, 0). Then recuse another level just in case the sum is multi-digit too.

Note that squiggigle operator ~~ (my term, not sure if it's got a name already) reliably converts a value to an signed 32-bit int in a bit less space than doing it properly, it's pretty much the same as the bang bang op !!, just with bitwise negation. It's used here since char is a string, ~~char get's the string's parsed number.

Collapse
willsmart profile image
willsmart

Here's my take on the modulus one, keeping with the nsfw JS syntax theme

muckle = n => n  && (n%9 || 9)
Collapse
dry profile image
Hayden Mankin

I've always liked this problem because of the n%9 trick, it's such a neat mathematical property.

I thought I'd do the obligatory n%9 solution:

let digital_root = (n) => n == 0 ? 0 : (n - 1) % 9 + 1;

console.log(digital_root(456)); // 6
console.log(digital_root(16));  // 7

As well as a one line recursive solution that doesn't use the n%9 trick:

let digital_root = (n) => (n < 10) ? n : digital_root(Array.from(n.toString()).map(Number).reduce((a, b)=>a+b));

console.log(digital_root(456)); // 6
console.log(digital_root(16));  // 7
Collapse
tam360 profile image
Mirza

Here's my solution:

def digital_root(num):
    num = str(num)

    if len(num) == 1:
        return int(num)
    else:
        temp = str(int(num[0]) + int(num[1]))
        return digital_root(temp + num[2: len(num)])
Collapse
saswat01 profile image
saswat

Simple python answer:
Alt code

Collapse
hitolv4 profile image
Viclv4
def digital_root(number):
    n = number
    while len(str(n)) != 1:
        n = sum([int(i) for i in str(n)])
    return n