1. Overview
A number is a magic number if the recursive sum of its digits is one. In this tutorial, let’s look at how we can check this in Scala.
2. Problem Statement
As mentioned in the previous section, we’ll check if a number is a magic number. In this context, we assume that the number is positive. As a result, we take the absolute value for the calculation to ensure this assumption.
Let’s see some sample cases before getting started with the implementation.
The number 654 isn’t a magic number since the sum of digits isn’t1 ( 6 + 5 + 4 = 15; 1 + 5 = 6)
On the other hand, 100 is a magic number since the sum of its digits(1 + 0 + 0 = 1) is 1.
3. Solutions
Let’s look at various ways this can be checked in Scala. In all cases, we can split the implementation into two parts: a function to calculate the sum of digits and another function to check if the sum is 1.
3.1. Using Recursion
We can use recursion to calculate the sum of the digits. In this case, we can use tail recursion to make sure that the implementation is safer by optimizing the code and reducing the stack calls to one:
def sumOfDigitsUsingRecursion(num: Long): Long = {
@tailrec
def recursiveSum(num: Long, sum: Long): Long = {
num match {
case 0 if sum < 10 => sum
case 0 if sum >= 10 => recursiveSum(sum / 10, sum % 10)
case n => recursiveSum(n / 10, sum + (num % 10))
}
}
recursiveSum(num, 0)
}
We use the integer division and modulo logic to extract each digit from the number. Additionally, we invoke the same method with the resultant sum if it’s not a single-digit number.
Now we can check if the number is a magic number easily:
assert(sumOfDigitsUsingRecursion(100) == 1)
3.2. Using Recursion and asDigit()
Another approach to extract the digit is converting the number into a String and using map() on each digit. We can then use the in-built sum() method to calculate the sum:
@tailrec
def sumOfDigitsUsingAsDigit(num: Long): Long = {
if (num < 10) {
// If the number is a single digit, return it
num
} else {
// Calculate the sum of digits recursively
val digitSum = num.toString.map(_.asDigit).sum
sumOfDigitsUsingAsDigit(digitSum)
}
}
Here, we invoke the method recursively with the sum value until it’s reduced to a single digit:
assert(sumOfDigitsUsingAsDigit(100) == 1)
3.3. Using Recursion and foldLeft()
This approach is very similar to the previous solution. Instead of using the sum() method directly, we can use foldLeft() to calculate the sum. We then make use of recursion to reduce the sum to a single-digit value:
@tailrec
def sumOfDigitsUsingFold(num: Long): Long = {
def sum = num.toString.foldLeft(0)((acc, dig) => acc + dig.asDigit)
if (sum < 10) sum else sumOfDigitsUsingFold(sum)
}
Again, we can test the method in the same way:
assert(sumOfDigitsUsingFold(100) == 1)
3.4. Using Iterator
Now, let’s look at a different approach to calculating the sum using Iterator:
def sumOfDigitsUsingIterator(num: Long): Long = {
Iterator
.iterate(num)(currentNum => currentNum.toString.map(_.asDigit).sum)
.dropWhile(_ >= 10)
.next()
}
Here, we create an infinite iterator that repeatedly applies the given function. In this case, we initialize an iterator with the input number and then calculate the sum of the digits of that number. We chain a dropWhile() method, which checks if the sum is a two-digit number. As a result, the iterator recalculates the sum until it becomes a single-digit number. Ultimately, we extract the value from the iterator by calling the next() method.
We can test this method in the same way:
assert(sumOfDigitsUsingIterator(100) == 1)
4. Conclusion
In this article, we explored different ways to check if a number is a magic number. Scala Collections are very powerful, and hence, there may be even more ways to calculate the sum of digits.
As always, the sample code used in this article is available over on GitHub.