Given an integer, produce a list of its digits

I need to turn an integer into a list of digits.

For example, given 1234 as input, the output should be [1, 2, 3, 4].

I am doing this right now, but it looks ugly and might even be inefficient.

  def get_check_digit(digits) when is_binary(digits) or is_integer(digits) do
    digits
    |> to_charlist()
    |> Enum.map(fn char ->
      {integer, []} = :string.to_integer([char])
      integer
    end)
    |> get_check_digit()
  end

  def get_check_digit(digits) when is_list(digits) do
    ...
  end

Any tips?

1 Like

How about Integer.digits/2 ?

5 Likes

Nice! Thanks

1 Like

Integer.digits/2 is certainly the easiest way to do this but I took a stab at this and wrote two versions:

Make use of codepoints

The first version is super short and basically makes use of the fact that charlists boil down to a list of integers (where the characters have their corresponding ASCII values).

iex> 1234 |> to_charlist() |> Enum.map(& &1 - ?0)
[1, 2, 3, 4]

By converting the number to a charlist, we have a list of codepoints. From here we can subtract the codepoint value of 0 (?0 which is 48) to get the actual numerical value.

Use math and recursion

The second solution uses a combination of integer division and the modulo operation. But see for yourself:

defmodule Digits do
  def digits(number) when number < 0, do: digits(-number)

  def digits(number) when is_integer(number) do
    calc(number, [])
  end

  defp calc(digit, digits)
    when digit < 10,
    do: [digit | digits]

  defp calc(number, digits) do
    digit = Integer.mod(number, 10)

    number
    |> div(10)
    |> calc([digit | digits])
  end
end

IO.inspect Digits.digits(1234), charlists: :as_lists

Here we get a single digit by doing number % 10 (which is Integer.mod/2 in Elixir), then we do the same for the next digit by dividing through 10. If we reach anything smaller than 10 we add it to the list and were done.

4 Likes

Am I missing something here? :smile: Isn’t :erlang.integer_to_list/1/2 the easiest and fastest? Though it would give a “bad” error value if the argument is not an integer.

1 Like

Aaaaagh. I’m just now getting back into this ecosystem after a long hiatus. My search game is very weak right now.

:erlang.integer_to_list returns charlist

> :erlang.integer_to_list(123123)
'123123'
> Integer.digits(123123)
[1, 2, 3, 1, 2, 3]
1 Like

Yes, I realised that later. :smile:

1 Like