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
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).
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.
Am I missing something here? 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.