Converting a given number to a word using array - ruby

I am trying to create a method for the classic bottles of beers output.
Given a number, #beers, I want to convert it to the word version of the number. I wanted to split the number into an array and then compare with a list of numbers to words:
class BeerSong
attr_accessor :beers
def initialize(beers)
if beers > 99
beers = 99
elsif beers < 1
beers = "Zero"
end
#beers = beers
end
def worded
num_name = {
90 => "Ninety", 80 => "Eighty", 70 => "Seventy",60 => "Sixty",
50 => "Fifty",40 => "Forty",30 => "Thirty",20 => "Twenty",
19 => "Nineteen", 18 => "Eighteen", 17 => "Seventeen", 16 => "Sixteen",
15 => "Fifteen",14 => "Fourteen", 13 =>"Thirteen", 12 => "Twelve",
11 => "Eleven", 10 => "Ten", 9 => "Nine",8 => "Eight", 7 => "Seven",
6 => "Six",5 => "Five",4 => "Four",3 => "Three",2 => "Two",1 => "One"
}
worded = ""
beers = #beers
split_beers = beers.to_s.split
num_name.each do |number, name|
split_number = number.to_s.split
if beers == number
worded << name
else
number > 19 && split_number[0].to_i == split_beers[0].to_i
worded << name
worded << "-"
end
end
num_name.each do |number, name|
if number < 10 && split_beers[1].to_i == number
worded << name
end
end
worded
end
def print_song
while #beers.to_i > 2
puts "#{worded} bottles of beer on the wall,"
puts "#{worded} bottles of beer,"
puts "Take one down, pass it around,"
#beers -= 1
puts "#{worded} bottles of beer on the wall.\n\n"
end
if #beers.to_i == 2
puts "#{worded} bottles of beer on the wall,"
puts "#{worded} bottles of beer,"
puts "Take one down, pass it around,"
#beers -= 1
puts "#{worded} bottle of beer on the wall.\n\n"
end
if #beers.to_i == 1
puts "#{worded} bottle of beer on the wall,"
puts "#{worded} bottle of beer,"
puts "Take one down, pass it around,"
puts "Zero bottles of beer on the wall.\n\n"
end
if #beers.to_i == 0
print ""
end
end
end
I am trying to compare the first digit to get the tens, then compare the second digit for the units separated by a hyphen.

Your lines:
split_beers = beers.to_s.split
split_number = number.to_s.split
assume an array as a result which is not the case because you don't provide a pattern to split on
so the default is used. See: http://ruby-doc.org/core-2.0.0/String.html#method-i-split
puts "10".to_s.split.inspect # gives ==> ["10"]
puts "10".to_s.split('',2).inspect # gives ==> ["1", "0"]
The last is what you want.

Related

Ruby: Food Menu that calculates and displays balance of your choice

Below is a method that displays a menu using a hash. I can't figure out how to use the input to then calculate and display the balance of the users choice/s. I'm also struggling with the concept of class initialization and how that could help here. Any help very welcome!
def product_menu
product_menu_hash = {
"Coffee" => 4.00,
"Soft Drink" => 4.00,
"Sandwich (Meat)" => 9.50,
"Sandwich (Veg)" => 8.00,
"Coffee Maker" => 50.00,
"Bag of Coffee (250g)" => 13.25,
}
puts "COFFEE SHOP"
product_menu_hash.each_with_index do |(item, price), index|
puts "#{index + 1} #{item} = $#{price}"
input = gets.chomp
end
end
If users enter quantities of items as integers
tot = 0
product_menu_hash = {
"Coffee" => 4.00,
"Soft Drink" => 4.00,
"Sandwich (Meat)" => 9.50,
"Sandwich (Veg)" => 8.00,
"Coffee Maker" => 50.00,
"Bag of Coffee (250g)" => 13.25,
}
puts "COFFEE SHOP"
product_menu_hash.each_with_index do |(item, price), index|
puts "#{index + 1} #{item} = $#{price}"
input = gets.chomp
totpar = input.to_i * price
puts totpar
tot += totpar
end
puts 'total: ', tot
The user is the shop assistant and I imagined them just entering the
menu choice e.g. 1 for Coffee or 2 for soft drink etc then the price
being calculated from there. Is there a way to do this?
Based on your last comment, a second answer would be
tot = 0
product_menu_hash = {
"Coffee" => 4.00,
"Soft Drink" => 4.00,
"Sandwich (Meat)" => 9.50,
"Sandwich (Veg)" => 8.00,
"Coffee Maker" => 50.00,
"Bag of Coffee (250g)" => 13.25,
}
product_choice = {}
product_menu_hash.each_with_index do |(item, price), index|
product_choice[index+1]=item
puts "#{index + 1} #{item} = $#{price}"
end
puts 'x to exit, p to print total '
choice = gets.chomp
while choice != 'x' do
if choice == 'p' then
puts 'total: ', tot
else
puts product_choice[choice.to_i],product_menu_hash[product_choice[choice.to_i]]
tot += product_menu_hash[product_choice[choice.to_i]]
end
choice = gets.chomp
end

Ordinal numbers in Ruby

My code works perfectly on everything except 11, 12 and 13 or numbers that end in those last two digits.
def ordinal()
n = gets.chomp.to_i
suffix = n % 10
if suffix == 1
return "That's the #{n}st item!"
elsif suffix == 2
return "That's the #{n}nd item!"
elsif suffix == 3
return "That's the #{n}rd item!"
else
return "That's the #{n}th item!"
end
end
Any help would greatly appreciated! Thank you.
This is a special case. Check 2 digit suffix before you check 1 digit suffix. Something like this
def ordinal(n)
ending = case n % 100
when 11, 12, 13 then 'th'
else
case n % 10
when 1 then 'st'
when 2 then 'nd'
when 3 then 'rd'
else 'th'
end
end
"This is #{n}#{ending} item"
end
ordinal(1) # => "This is 1st item"
ordinal(10) # => "This is 10th item"
ordinal(12) # => "This is 12th item"
ordinal(15) # => "This is 15th item"
ordinal(112) # => "This is 112th item"
ordinal(123) # => "This is 123rd item"

How to convert number to word in ruby without using any gem? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I have a number say 100 i want it converted into one hundred in word.similary for floating point say 0.0 is zero and 3.4 to three point four
There are many gems available which convert number to word:
gem 'to_words'
humanize
numbers_and_words
But as you don't want to use gem I found something like (without any gem):
class Fixnum
def english_word
#h = { 0=>"zero", 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=>"Fourty",50=>"Fifty",60=>"Sixty",70=>"Seventy", 80=>"Eighty",90=>"Ninty" }
#i=0
#array=[]
#result=""a
if self > 99
str_num=self.to_s ##num.to_s
str_num_len=str_num.length
str_full_num=str_num.insert(0,"0"*(11-str_num_len))
str_full_num=str_num.insert(8,"0")
str_full_num.scan(/../) { |x| #array<<x }
6.times do
self.def_calc
#i+=1
end
else
if self > 9
puts (self.proc_double_dig((self/10)*10)) + (self.proc_single_dig(self%10))
else
if self > 0
puts self.proc_single_dig(self)
else
return "AMOUNT NOT KNOWN or NILL"
end
end
end
end
def def_calc
case #i
when 0
str=self.proc_unit(#array[#i])
if (str.scan(/\w+/)).length!=0
then str=str+ "hundred & "
#result=#result+str
end
when 1
str=self.proc_unit(#array[#i])
if (str.scan(/\w+/)).length!=0
then str=str+ " Crore, "
#result=#result+str
end
when 2
str=self.proc_unit(#array[#i])
if (str.scan(/\w+/)).length!=0
then str=str+ " Lakh, "
#result=#result+str
end
when 3
str=self.proc_unit(#array[#i])
if (str.scan(/\w+/)).length!=0
then str=str+ " Thousand, "
#result=#result+str
end
when 4
str=self.proc_unit(#array[#i])
if (str.scan(/\w+/)).length!=0
then str=str+ " Hundred, "
#result=#result+str
end
when 5
str=self.proc_unit(#array[#i])
if (str.scan(/\w+/)).length!=0
then str=str+ ". "
#result=#result+str
end
print #result.sub(/..$/,"")
else
end
end
def proc_unit(x)
if x.to_i>0
if x.to_i<=10
return self.proc_single_dig(x.to_i)
else
if x.to_i<=20
return self.proc_double_dig(x.to_i)
else
return (self.proc_double_dig((x.to_i/10)*10)) + (self.proc_single_dig(x.to_i%10))
end
end
end
return ""
end
def proc_double_dig(z)
if z==0
return ""
else
return #h[z]
end
end
def proc_single_dig(y)
if y==0
return ""
else
return #h[y]
end
end
protected :def_calc, :proc_unit, :proc_double_dig,
:proc_single_dig
end
puts 453645445.english_word
#FourtyFive Crore, Thirtysix Lakh, FourtyFive Thousand,Four Hundred,FourtyFive
Reference Taken from : https://raveendran.wordpress.com/2009/05/29/ruby-convert-number-to-english-word/
I hope it helps you :)
This is what i have found solution . i hope this will help others.
def in_words(int)
numbers_to_name = {
10**18 => "quintillion", 10**15 => "quadrillion", 10**12 => "trillion",
10**9 => "billion", 10**6 => "million", 1000 => "thousand", 100 => "hundred",
90 => "ninety", 80 => "eighty", 70 => "seventy", 60 => "sixty", 50 => "fifty",
40 => "forty", 30 => "thirty", 20 => "twenty", 19=>"nineteen",
18=>"eighteen", 17=>"seventeen", 16=>"sixteen", 15=>"fifteen",
14=>"fourteen", 13=>"thirteen", 12=>"twelve", 11 => "eleven", 10 => "ten",
9 => "nine", 8 => "eight", 7 => "seven", 6 => "six", 5 => "five",
4 => "four", 3 => "three", 2 => "two", 1 => "one"
}
str = ""
numbers_to_name.each do |num, name|
if int == 0
return str
elsif int.to_s.length == 1 && int/num > 0
return str + "#{name}"
elsif int < 100 && int/num > 0
return str + "#{name}" if int%num == 0
return str + "#{name} " + in_words(int%num)
elsif int/num > 0
return str + in_words(int/num) + " #{name} " + in_words(int%num)
end
end
end
def words_from_numbers number
fix = number.to_i == 0 ? "zero" : in_words(number.to_i).strip.gsub('hundred ','hundred and ')
frac = number - number.to_i == 0 ? "" : " point one"
fix + frac
end

Difference between + and << in Ruby

Below are two identical classes with the difference of the operators + and <<. These can be found in the inject method. In the + case the tests pass and in the << some of them fail. Why?
class Integer
ROMAN_NUMERALS = {
0 => '',
1 => 'I', 2 => 'II', 3 => 'III', 4 => 'IV', 5 => 'V', 6 => 'VI', 7 => 'VII', 8 => 'VIII', 9 => 'IX',
10 => 'X', 20 => 'XX', 30 => 'XXX', 40 => 'XL', 50 => 'L', 60 => 'LX', 70 => 'LXX', 80 => 'LXXX', 90 => 'XC',
100 => 'C', 200 => 'CC', 300 => 'CCC', 400 => 'CD', 500 => 'D', 600 => 'DC', 700 => 'DCC', 800 => 'DCCC', 900 => 'CM',
1000 => 'M', 2000 => 'MM', 3000 => 'MMM'
}
def to_roman
to_s.reverse.chars.each_with_index.inject("") do |roman_numeral, (character, index)|
ROMAN_NUMERALS[character.to_i * 10 ** index] << roman_numeral
end
end
end
I get different results to when I run
class Integer
ROMAN_NUMERALS = {
0 => '',
1 => 'I', 2 => 'II', 3 => 'III', 4 => 'IV', 5 => 'V', 6 => 'VI', 7 => 'VII', 8 => 'VIII', 9 => 'IX',
10 => 'X', 20 => 'XX', 30 => 'XXX', 40 => 'XL', 50 => 'L', 60 => 'LX', 70 => 'LXX', 80 => 'LXXX', 90 => 'XC',
100 => 'C', 200 => 'CC', 300 => 'CCC', 400 => 'CD', 500 => 'D', 600 => 'DC', 700 => 'DCC', 800 => 'DCCC', 900 => 'CM',
1000 => 'M', 2000 => 'MM', 3000 => 'MMM'
}
def to_roman
to_s.reverse.chars.each_with_index.inject("") do |roman_numeral, (character, index)|
ROMAN_NUMERALS[character.to_i * 10 ** index] + roman_numeral
end
end
end
The tests I am using are below
require 'minitest/autorun'
require_relative 'roman'
class RomanTest < MiniTest::Unit::TestCase
def test_1
assert_equal 'I', 1.to_roman
end
def test_2
assert_equal 'II', 2.to_roman
end
def test_3
assert_equal 'III', 3.to_roman
end
def test_4
assert_equal 'IV', 4.to_roman
end
def test_5
assert_equal 'V', 5.to_roman
end
def test_6
assert_equal 'VI', 6.to_roman
end
def test_9
assert_equal 'IX', 9.to_roman
end
def test_27
assert_equal 'XXVII', 27.to_roman
end
def test_48
assert_equal 'XLVIII', 48.to_roman
end
def test_59
assert_equal 'LIX', 59.to_roman
end
def test_93
assert_equal 'XCIII', 93.to_roman
end
def test_141
assert_equal 'CXLI', 141.to_roman
end
def test_163
assert_equal 'CLXIII', 163.to_roman
end
def test_402
assert_equal 'CDII', 402.to_roman
end
def test_575
assert_equal 'DLXXV', 575.to_roman
end
def test_911
assert_equal 'CMXI', 911.to_roman
end
def test_1024
assert_equal 'MXXIV', 1024.to_roman
end
def test_3000
assert_equal 'MMM', 3000.to_roman
end
end
See how the specs fail in one case but not in the other. I thought these are meant to work in the same way.
This line is a problem...
ROMAN_NUMERALS[character.to_i * 10 ** index] << roman_numeral
It will return a string which is the value of the correct ROMAN_NUMERALS key plus roman_numeral, which is what you want, BUT it is also changing the value in the ROMAN_NUMERALS hash! The shovel operator << changes the string on the left of the operator (it's what we call a mutating operator).
So if you test for 1001 the unit 1 will return "I" (that's fine) then the zero will return an empty string BUT will change the value for zero into "I"... the second zero will return "I" (incorrect) and will change the value for zero into "II". The 1 in the thousands position will return "M" but then change the hash value into "MII".
When the line ROMAN_NUMERALS[character.to_i * 10 ** index] << roman_numeral is being executed you are replacing the value corresponding to the key character.to_i * 10 ** index with its value plus roman_numeral.
Now that your question has been answered, I would like to suggest an alternative method and also a different way to perform your tests. This requires Ruby v1.9+, so we can depend on the order of the hash keys.
Code
First, reverse the order of the hash elements.
RNR = Hash[ROMAN_NUMERALS.to_a.reverse]
#=> {3000=>"MMM", 2000=>"MM", 1000=>"M",..., 2=>"II", 1=>"I", 0=>""}
Then:
class Integer
def to_roman
num = self
roman = ""
while num > 0
i,r = RNR.find { |i,r| i <= num }
roman << r
num -= i
end
roman
end
end
Test objectives
We need to test a substantial number of integer values and make sure that we are testing each integer against the correct roman numeral equivalent. Both of these objectives can be met by creating a method that converts roman numerals to integers:
RNRI = RNR.invert
#=> {"MMM"=>3000, "MM"=>2000, "M"=>1000,..., "II"=>2, "I"=>1, ""=>0}
class String
def roman_to_integer
num = 0
roman = self
while roman.size > 0
r, i = RNRI.find { |r,m| roman =~ /^#{r}/ }
num += i
roman = roman[r.size..-1]
end
num
end
end
Examples
Now let's invoke both Integer#to_roman and String#roman_to_integer for various integer values:
def check_one(i)
roman = i.to_roman
puts "#{i}.to_roman = #{roman}, #{roman}.roman_to_integer = " +
#{roman.roman_to_integer}"
end
check_one(402) # 'CDII'
# 402.to_roman = CDII, CDII.roman_to_integer = 402
check_one(575) # 'DLXXV'
# 575.to_roman = DLXXV, DLXXV.roman_to_integer = 575
check_one(911) # 'CMXI'
# 911.to_roman = CMXI, CMXI.roman_to_integer = 911
check_one(1024) # 'MXXIV'
# 1024.to_roman = MXXIV, MXXIV.roman_to_integer = 1024
check_one(3000) # 'MMM'
# 3000.to_roman = MMM, MMM.roman_to_integer = 3000
Tests
So now in your testing you can use:
def test_all(n)
(1..n).each { |i| test_one(i) }
end
def test_one(i)
roman = i.to_roman
assert_equal(i, roman.roman_to_integer, "#{i}.to_roman=#{roman}, " +
"#{roman}.roman_to_integer = #{roman.roman_to_integer}")
end

Trouble looping string with 99 bottles of beer

I was able to count down to 97 bottle of beers but I am having trouble looping to count down to 1. Is it possible to create a loop with what I wrote? Here's what I have so far.
all_beers = (99).to_s
one_less = ((all_beers).to_i - 1).to_s
puts '' +
all_beers + ' bottles of beer on the wall, ' +
all_beers + ' bottles of beer. You take one down you pass it around ' +
one_less + ', beers on the wall!'
all_beers = one_less
one_less = ((all_beers).to_i - 1).to_s
puts '' +
all_beers + ' bottles of beer on the wall, ' +
all_beers + ' bottles of beer. You take one down you pass it around ' +
one_less + ', beers on the wall!'
use downto :
it will loop from the number you want upto the number you wish.
99.downto(1).each do |s|
all_beers = s
one_less = s - 1
puts '' +
all_beers.to_s + ' bottles of beer on the wall, ' +
all_beers.to_s + ' bottles of beer. You take one down you pass it around ' +
one_less.to_s + ', beers on the wall!'
end
Yes, it is certainly possible. This is taken from 99 Bottles of Beer project:
#
# Rubeer.rb
# by Eric Budd, Jan. 2008
#
# Demonstrates adding functionality to a built-in class, optional method parameters, inline
# conditionals, string replacement, alcohol aversion, and excessively fancy use of hashes.
#
# This borrows the hash from Daniel Straight's excellent implementation for the "wordalize" method
#
class Integer
NUMBER_WORDS = { 0 => "no", 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"}
def wordalize
raise "Invalid number to wordalize - should be in the range (0..99)" unless (0..99) === self
return NUMBER_WORDS[self] if self < 20
wordalized = NUMBER_WORDS[self - (self % 10)]
wordalized += '-' + NUMBER_WORDS[self % 10] unless (self % 10) == 0
return wordalized
end
def bottles
raise "Invalid number of bottles - should be in the range (0..99)" unless (0..99) === self
how_many_bottles = self.wordalize + ' bottle'
how_many_bottles += 's' unless self == 1
return how_many_bottles
end
alias :bottle :bottles # for grammar Nazis
end
def sing(number, teetotaller = false)
beverage = teetotaller ? 'coke' : 'beer'
puts "#{number.bottles.capitalize} of #{beverage} on the wall, #{number.bottles} of #{beverage}."
if number != 0
puts "Take one down, pass it around, #{(number - 1).bottles} of #{beverage} on the wall.\n\n"
else
puts "Go to the store and buy some more, 99 bottles of #{beverage} on the wall."
end
end
99.downto(0) { |number| sing(number) }
# Uncomment the following for the alternative teetotaller version
# 99.downto(0) { |number| sing(number, true) }
There are multiple Ruby versions uploaded there, but the default one is too complicated for beginners. This one, though, is very nice, and you should be able to understand what is going on.
The point that should answer your question is the bit with 99.downto(0) { |number| ... }. This is a loop that will repeat anything within the braces (in this case, sing(number)) a hundred times, with number going from 99 to 0.
Also note that it is inefficient (and illegible) to carry around the number as a string ((99).to_s) and convert it back to integer when you need it; rather, have it always be an integer, and convert it to string just before you need it as a string, when you display (or have the string concatenation/interpolation do it for you automatically, as in this piece of code).
While Ruby does have both for and while loops, they are rarely (while) or never (for) used. Instead, Rubyists usually rely on iterators and enumerators. Other functions like Integer#downto are Integer#upto, Integer#times and pretty much everything in the most awesome Enumerable mixin.
The short answer is yes, you can make a loop using what you wrote, and there are many ways of looping with ruby. However, since this seems to be about learning programming, considering that you did not use any control structures or string interpolation, not to mention casting that doesn't make much sense, I'd recommend Why's Poignant Guide to Ruby to learn the concepts of programming while using ruby.
As well as downto, you could do something like:
(1..99).reverse_each do |number|
bottle = number == 1 ? 'bottle' : 'bottles'
verse = "#{number} #{bottle} of beer on the wall, #{number} #{bottle} of beer. "
verse << "Take one down, pass it around, #{number-1} #{number-1 == 1 ? 'bottle' : 'bottles'} of beer on the wall"
puts verse
end
Things you may use to make your life easier: downto(), proc, ternary if (--that--thing--> ?:)
I enjoyed experiencing this exercise for the first time, so I'm a little hesitant about providing an answer here but so it goes.
It's a little bit more advanced, but using a 'proc' to make sure you pluralize "bottle(s)" correctly is a nice and clean way to get it done.
'downto()' is also an awesome way to iterate through those 99 bottles since it makes it feel like you're reading English instead of code.
num_at_start = 99 # You may change this number.
num_bottles = proc { |n| "#{n} bottle#{ n == 1 ? '' : 's'}" }
num_at_start.downto(1) do |num|
print "#{num_bottles.call(num)} of beer on the wall, " +
"#{num_bottles.call(num)} of beer!\n" +
"You take one down, pass it around, "
unless num == 1
puts "#{num_bottles.call(num - 1)} of beer on the wall!"
else
puts "No more bottles of beer on the wall!"
end
end
Source: Learn to Program 2nd Edition by Chris Pine (I changed a couple of things though)
This is the fix that I found for this question:
beer = 99
while beer > 0
puts beer.to_s + " bottles of beer on the wall. " + beer.to_s +
" bottles of beer."
(beer -= 1).to_s
puts "Take one down, pass it around. " + beer.to_s +
" bottles of beer on the wall."
end

Resources