1

I'm studying functional programming with Elixir and came across the following exercise:

"You are given a two-digit integer n. Return the sum of its digits."

The solution I came up looks a bit "hairy". I wonder if someone could give some advice into Elixir std lib functions/module and provide a better solution. I know I could just go with n%10 + Math.floor(n/10)(js) but Id' like to know if a solution using Elixir functions would be more or less what I came up with:

def addTwoDigits(n) do
   n |> Integer.to_string 
     |> String.split("") # Number 44 would give a list ["",4,4,""]
     |> Enum.filter(&(&1 != ""))
     |> Enum.map(&(String.to_integer(&1)))
     |> Enum.reduce(&(&1+&2))
end
Ronan Boiteau
  • 9,608
  • 6
  • 34
  • 56
Heron Rossi
  • 681
  • 6
  • 18

3 Answers3

2

Easiest and closest to your initial thought, would be by leveraging the following function:

Integer.digits(123)
[1, 2, 3]

to obtain each individual digit as documented here

You can then simply do:

def sum_digits_in_number(n) do
   n
   |> Integer.digits
   |> Enum.sum
end
Kevin Johnson
  • 1,890
  • 13
  • 15
1

You should avoid unnecessary operations (conversion to string, conversion to list, etc.).

I'd go with the following, using div/2 & rem/2 in a recursive function:

def addTwoDigits(n) do
  if n > 0, do: rem(n, 10) + addTwoDigits(div(n, 10)), else: n
end

I used this to compare our functions:

  • your function runs in ~16 μs
  • the function above runs in ~4 μs

By working with integers you avoid useless conversions/iterations & get a function that computes your result ~4 times faster!

Ronan Boiteau
  • 9,608
  • 6
  • 34
  • 56
  • 1
    Be careful of premature optimization. How important is a factor of 4 speed improvement on learning code that someone's doing to learn FP? – Onorio Catenacci May 15 '18 at 20:59
1

Since it’s an exercise / learning example, I would assume the answer expected would be a function with many clauses:

defmodule M do
  def add(num, acc \\ 0)
  def add(num, _acc) when num > 99, do: raise("Invalid #{num}")
  def add(num, acc) when num < 10, do: acc + num
  def add(num, acc), do: add(rem(num, 10), acc + div(num, 10))
end

IO.puts M.add(35)
#⇒ 8
IO.puts M.add(5)
#⇒ 5
IO.puts M.add(88)
#⇒ 16
IO.puts M.add(101)
#⇒ ** (RuntimeError) Invalid 101

This is definitely a huge overkill for this particular task, but think how easy is to make this code to sum integers having 3 numbers (unlike any other non-functional approach.)

Aleksei Matiushkin
  • 119,336
  • 10
  • 100
  • 160