Skip to content

Instantly share code, notes, and snippets.

@neenjaw
Last active November 8, 2019 16:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save neenjaw/9ec37872ef6cf5f091f5f67f8dc23f52 to your computer and use it in GitHub Desktop.
Save neenjaw/9ec37872ef6cf5f091f5f67f8dc23f52 to your computer and use it in GitHub Desktop.
Say refactor
# Originally created by @angelikatyborska, https://github.com/angelikatyborska
# Extended by me
defmodule Say do
@min 0
@max 999_999_999_999
@base_cases_map %{
1 => "one",
2 => "two",
3 => "three",
4 => "four",
5 => "five",
6 => "six",
7 => "seven",
8 => "eight",
9 => "nine",
10 => "ten",
11 => "eleven",
12 => "twelve",
13 => "thirteen",
14 => "fourteen",
15 => "fifteen",
16 => "sixteen",
17 => "seventeen",
18 => "eighteen",
19 => "nineteen",
20 => "twenty",
30 => "thirty",
40 => "forty",
50 => "fifty",
60 => "sixty",
70 => "seventy",
80 => "eighty",
90 => "ninety"
}
# I redefine the module attribute using the module attribute as a base
# Not sure if it makes it shorter, but it removes the need for the
# extra function clause later
@base_cases_map Enum.reduce(1..99, @base_cases_map, fn n, base_cases ->
if base_cases[n] do
base_cases
else
[tens, ones] = Integer.digits(n)
Map.put(base_cases, n, "#{base_cases[tens]}-#{base_cases[ones]}")
end
end)
@base_cases Map.keys(@base_cases_map)
@big_numbers %{
100 => "hundred",
1_000 => "thousand",
1_000_000 => "million",
1_000_000_000 => "billion"
}
@doc """
Translate a positive integer into English.
"""
@spec in_english(integer) :: {atom, String.t()}
def in_english(number) when number < @min or number > @max do
{:error, "number is out of range"}
end
def in_english(0) do
{:ok, "zero"}
end
def in_english(number) do
{:ok, do_in_english(number)}
end
defp do_in_english(0) do
""
end
for big_number <- Enum.sort_by(Map.keys(@big_numbers), &(-1 * &1)) do
defp do_in_english(number) when number >= unquote(big_number) do
head = Integer.floor_div(number, unquote(big_number))
rest = number - head * unquote(big_number)
[
"#{do_in_english(head)} #{@big_numbers[unquote(big_number)]}",
do_in_english(rest)
]
|> Enum.filter(&(&1 != ""))
|> Enum.join(" ")
end
end
defp do_in_english(number) when number in @base_cases do
@base_cases_map[number]
end
# defp do_in_english(number) when number in 21..99 do
# [tens, ones] = Integer.digits(number)
# "#{do_in_english(tens * 10)}-#{do_in_english(ones)}"
# end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment