Integers to English Words

Hi,

I’m a junior software engineer who has been blessed with the gift of
Ruby as my introductory language. However, I’m a little anxious about a
coding test I have been asked to do…convert numbers to english words.
My solution is below which I was pretty pleased with…but I have to
present it and explain what it is that I could have done better. I was
hoping some of you could take a look and offer your opinions?

$hash = Hash[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”, 100 => “hundred”, 1000 => “thousand”]

class Integer
def to_words
str = “”
num = self

if num >= 1000000
  millions = num/1000000
  str += millions.to_words + " million"
  str += " "
  num = num - millions*1000000
end

if num >= 1000
  thousands = num/1000
  str += thousands.to_words + " thousand "
  num = num - thousands*1000
end

if num >= 100
  hundreds = num/100
  str += $hash[hundreds] + " hundred"
  if (num-hundreds*100) > 0
    str += " and "
  end
  num = num - hundreds*100
end

if num > 0
  if num <= 19
    str += $hash[num]
  else
    tenths = num
    num = num / 10
    if num > 0
      str += $hash[num*10] + " "
    end
    if (tenths-num*10) > 0
      str += $hash[tenths-num*10]
    end
  end
end
str

end
end

decode = nil
puts “Enter ‘decode x’ replacing x with an integer between 1 and
999999999. Simply type 0 to finish:”
decode = gets.gsub(/[a-zA-Z]+\s/, ‘’).to_i
puts decode.to_words

while (1…999999999).include?(decode)
puts “Enter ‘decode x’ replacing x with an integer between 1 and
999999999. Simply type 0 to finish:”
decode = gets.gsub(/[a-zA-Z]+\s/, ‘’).to_i
puts decode.to_words
end

Is this any help?

http://www.rubyquiz.com/quiz25.html

Harry

The linguistics gem might be what you want.

See dev(E)iate

Thanks Harry, that’s exactly the type of alternative (and write up) I
was after.

I should have said Peter, that no external libraries were allowed; it is
purely a test to see how I would tackle the ‘problem’.

  1. $hash
    Never use global variables. Instead, you can make that a constant
    inside Integer.

  2. end
    end
    str
    end
    end

str is hidden in your ends. You need to insert some blank lines in
there.

  1. The ‘and’ in the final result is improper.

nine hundred and fifty two million one hundred thousand fifty two

v.

nine hundred and fifty two million and one hundred thousand and fifty
two

v.

nine hundred fifty two million one hundred thousand fifty two

  1. 1000000 v. 1_000_000

num = num - 10

v.

num -= 10

  1. Use spacing or parentheses in your calculations:

tens = num/10*10

v.

tens = num/10 * 10

  1. You don’t need to recursively call your function.
  2. You can make your if_else decision tree more consistent and
    therefore easier to understand:

class Integer
NUMBER_TO_WORD = Hash[
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”,
100 => “hundred”,
1000 => “thousand”,
]

def hundreds_helper(num)
string_fragments = []

if num >= 100
  hundreds = num/100
  string_fragments << "%s hundred" % NUMBER_TO_WORD[hundreds]
  num -= hundreds*100
end

if num >= 20
  tens = num/10 * 10
  string_fragments << NUMBER_TO_WORD[tens]
  num -= tens
end

if num >= 11
  string_fragments << NUMBER_TO_WORD[num]
  num = 0
end

if num > 0
  string_fragments << NUMBER_TO_WORD[num]
end

string_fragments.join(' ');

end

def to_words
string_fragment= []
num = self

if num >= 1_000_000
  millions = num/1_000_000
  string_fragment << "%s million" % hundreds_helper(millions)
  num -= millions*1_000_000
end

if num >= 1_000
  thousands = num/1_000
  string_fragment << "%s thousand" % hundreds_helper(thousands)
  num -= thousands*1_000
end

string_fragment << hundreds_helper(num)
string_fragment.join(' ')

end
end

  1. Should you even be monkey patching Integer?? You could do the same
    thing but instead of calling:

1_000_000.to_words

you would write:

to_words(1_000_000)

This:

def hundreds_helper(num)

if num >= 11
  string_fragments << NUMBER_TO_WORD[num]
  num = 0
end

if num > 0
  string_fragments << NUMBER_TO_WORD[num]
end

can be changed to:

if num > 0
string_fragments << NUMBER_TO_WORD[num]
end

And this:

def to_words
string_fragment= []
num = self

if num >= 1_000_000
  millions = num/1_000_000
  string_fragment << "%s million" % hundreds_helper(millions)
  num -= millions*1_000_000
end

if num >= 1_000
  thousands = num/1_000
  string_fragment << "%s thousand" % hundreds_helper(thousands)
  num -= thousands*1_000
end

string_fragment << hundreds_helper(num)
string_fragment.join(' ')

end

can be changed to:

def to_words
string_fragments = []
num = self

if num >= 1_000_000
  millions = num/1_000_000
  string_fragments <<  "%s million" % hundreds_helper(millions)
  num -= millions*1_000_000
end

if num >= 1_000
  thousands = num/1_000
  string_fragments <<  "%s thousand" % hundreds_helper(thousands)
  num -= thousands*1_000
end

if num > 0
  string_fragments << hundreds_helper(num)
end

string_fragments.join(' ')

end