Home > other >  Recursively sum all digits until number is single digit
Recursively sum all digits until number is single digit

Time:06-13

For example, sum all the digits of 1253, 1 2 5 3 which is 11. This is two digits, so sum those again to get 2. The final number left is a single digit.

This is what I have so far:

defmodule Kata do
    def digital_root(n) do
    n |> Integer.digits() |> Enum.reduce(0, &Kernel. /2)
    end
end
n = 1253

CodePudding user response:

You can use a multi clause function for this: in the first one, return n unchanged if it's a single digit. Otherwise, compute the sum of digits (like you've already figured out) and recursively call the function on it again. Also, your reduce can be replaced with Enum.sum/1.

defmodule Kata do
  def digital_root(n) when n < 10, do: n
  def digital_root(n) do
    n |> Integer.digits() |> Enum.sum() |> digital_root()
  end
end

Test:

iex(1)> Kata.digital_root(0)
0
iex(2)> Kata.digital_root(1)
1
iex(3)> Kata.digital_root(9)
9
iex(4)> Kata.digital_root(91)
1
iex(5)> Kata.digital_root(912)
3
iex(6)> Kata.digital_root(9123)
6
iex(7)> Kata.digital_root(1253)
2

CodePudding user response:

  def digit_sum(number) when number < 10, do: number
  def digit_sum(number) when is_integer(number) do
    digit_sum(
      for digit <- Integer.digits(number), reduce: 0 do
        acc -> acc   digit
      end
    )
  end

I like Dogbert's better.

CodePudding user response:

Just for fun, here's a version that doesn't use Integer.digits/2 or Enum, and instead uses div/2 and rem/2 to calculate the least significant digit for each iteration:

defmodule Kata do
  # Function header
  def digital_root(to_sum, acc \\ 0)

  # Base case. All digits added, acc is a single digit
  def digital_root(0, acc) when div(acc, 10) == 0, do: acc

  # Finished a round. All digits added, acc is multiple digits. Sum again.
  def digital_root(0, acc), do: digital_root(acc, 0)

  # Split off the least significant digit, add it, and recurse
  def digital_root(to_sum, acc) do
    digit = rem(to_sum, 10)
    next_to_sum = div(to_sum, 10)
    digital_root(next_to_sum, acc   digit)
  end
end

Output:

iex> Kata.digital_root(1523)
2

In a benchmark, this version is twice as fast as dogbert's, and three times faster than 7stud's answers.

Name                ips        average  deviation         median         99th %
adam            14.26 M       70.13 ns  ±1898.51%       66.70 ns       83.30 ns
dogbert          7.08 M      141.28 ns ±14510.93%         125 ns         167 ns
sevenstud        4.83 M      206.98 ns ±15193.15%         167 ns         292 ns

Comparison:
adam            14.26 M
dogbert          7.08 M - 2.01x slower  71.14 ns
sevenstud        4.83 M - 2.95x slower  136.85 ns

Operating System: macOS
CPU Information: Apple M1 Pro
Number of Available Cores: 10
Available memory: 16 GB
Elixir 1.13.4
Erlang 24.3.4
  • Related