Last active
November 8, 2019 16:10
-
-
Save neenjaw/9ec37872ef6cf5f091f5f67f8dc23f52 to your computer and use it in GitHub Desktop.
Say refactor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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