puts 'Please insert a number between 1 and 100.'
num = gets.to_i
if (0..100).step(0) do |n|
# n = 10
# n = 20
# n = 30
# ...
puts 'Thanks. You inserted ' + num.to_s + '!'
# # using case
# case num2
# when 60
# puts "Student gets F grade"
# when 60..70
# puts "Student gets D grade"
# when 70..80
# puts "Student gets C grade"
# when 80..90
# puts "Student gets B grade"
# when 90..100
# puts "Student gets A grade"
# else
# puts "Grade not available for that value."
# end
else n => (100)
puts 'Please insert a number between 1 and 100.'
num = gets.to_i
puts 'Thanks. You inserted ' + num.to_s + '!'
end
the commented out code above is what I'm trying to eliminate and
accomplish with a for else loop in ruby.
Essentially I want to check if user enters a number within the
valid range (0 - 100) and then execute code associated with it, if user enters number outside of range to try again using else.
I want to spit out a letter grade correlating to the value entered.
So if valid value is entered -> get grade associated with -> else 'Please try again'. Any thoughts how to achieve this with a more
optimal loop, rather then my annoying multiple cases previous code?
update:
puts 'Please insert a number between 1 and 100.'
num = gets.to_i
while !num.between?(1, 100)
#num = gets.chomp.to_i
grade = loop do
puts 'Check your score!'
input = gets.to_i
case input
when 1..60
break 'F'
when 60..70
break 'D'
when 70..80
break 'C'
when 80..90
break 'B'
when 90..100
break 'A'
else
puts 'Please insert a VALID number between 1 and 100.'
num = gets.to_i
end
end
puts "Your grade is #{grade}"
end
I think you have the right idea with the case-expression. Just put it all into a loop and assign its return value to a variable. In the case-branches use break('grade')
grade = loop do
puts 'What\'s your score'
input = gets.to_i
case input
when 1..10
break 'F'
when 11..20
break 'E'
else
puts 'invalid score try again'
end
end
puts "Your grade is #{grade}"
This is one of many ways to obtain your desired result in a Ruby-like fashion.
NumberToLetter = [['F', 59], ['D', 69], ['C', 79], ['B', 89], ['A', 100]]
def letter_grade
num = number_grade
letter, _ = NumberToLetter.find { |_, n| num <= n }
[num, letter]
end
def number_grade
loop do
puts 'Please insert a number between 1 and 100.'
num = gets.to_i
break(num) if (1..100).cover?(num)
end
end
10.times { print letter_grade; puts }
# [43, "F"]
# [59, "F"]
# [60, "D"]
# [69, "D"]
# [70, "C"]
# [79, "C"]
# [80, "B"]
# [89, "B"]
# [90, "A"]
# [100, "A"]
The first element of each two-element array returned is the number entered by the user. The second is the associated grade.
I adopted the Ruby convention of representing a local variable that is not used in calculations with an underscore ('_'), which is in fact a valid variable name.
You're over-engineering this.
num = 0
while !num.between?(1, 100)
puts 'Please insert a number between 1 and 100.'
num = gets.chomp.to_i
end
puts "Thanks, #{num}"
It is simpler as you think, if now I understand, you just need to ask while the input of the user is in the range you want, if it is you skip the while and do what you want:
The full code would be:
puts 'Please insert a number between 1 and 100.'
num = gets.to_i
while not num.between?(0,100) do
puts 'Please insert a number between 1 and 100.'
num = gets.to_i
end
puts 'Thanks. You inserted ' + num.to_s + '!'
case num
when 60
puts "Student gets F grade"
when 60..70
puts "Student gets D grade"
when 70..80
puts "Student gets C grade"
when 80..90
puts "Student gets B grade"
when 90..100
puts "Student gets A grade"
else
puts "Grade not available for that value."
end
Related
I need help with loops.
I'm trying to capture the input from the user and determine a hotel's cost for planning a vacation.
I have a problem looping the input so the user can pick another hotel and end the program if the user does not pick any of the keystrokes ("A", "a", "B", "b", "C", "c", "D", or "d"), and then calculate the total cost for hotels.
I came up with this so far:
puts choice = gets.chomp.downcase
puts "For how many nights?"
num=gets.chomp.to_i
puts "Okay...any other hotels?"
puts choice = gets.chomp.downcase
#Hotel Prices
#Hotel A
if (choice== "a" or choice=="A")
cost_2= (num/3)*500 + (num%3)*200
end
#Hotel B
if (choice=="b" or choice=="B")
cost_3= num*250
end
#Hotel C
if (choice=="c" or choice=="C")
cost_4 = (num/3)*700 + (num%3)*300
end
#Hotel D
if (choice== "d" or choice=="D")
cost_5= num*500
end
Hotel Program
Wrap your code in a while loop,
continue = true
while continue
...
if choice == "done"
continue = false
end
end
Obviously the end case can be anything, not just "done".
For the sake of completion, an elegant solution to this problem would be something like:
loop do
puts choice = gets.chomp.downcase
puts "For how many nights?"
num=gets.chomp.to_i
puts "Okay...any other hotels?"
puts choice = gets.chomp.downcase
selections = {
a: (num/3)*500 + (num%3)*200,
b: num*250,
c: (num/3)*700 + (num%3)*300,
d: (num*500)
}
if selections[choice.to_sym]
cost += selections[choice.to_sym]
else
break
end
end
There are several possible improvements to your code, but I'll keep this answer as simple and direct as I can.
Use a loop, and a single if ... else if ... else ... end block code, rather than several separate if statements:
loop do
if (choice== "a" or choice=="A")
cost_2= (num/3)*500 + (num%3)*200
#Hotel B
elsif (choice=="b" or choice=="B")
cost_3= num*250
#Hotel C
elsif (choice=="c" or choice=="C")
cost_4 = (num/3)*700 + (num%3)*300
#Hotel D
elsif (choice== "d" or choice=="D")
cost_5= num*500
else
puts "Final cost is: [...]"
break
end
end
You could also consider implementing a more explicit exit by saying something like "Type 'done' when you have finished" -- and 'ignoring' any other input that is is not a/b/c/d/done. In other words, something along the lines of:
# ...
elsif (choice== "d" or choice=="D")
cost_5= num*500
elsif choice == 'done'
puts "Final cost is: [...]"
break
else
puts 'Unknown option'
end
# ...
This is untested, but it's the basic idea for what I'd use:
loop do
cost = nil
loop do
puts 'Which hotel? (A, B, C, D)'
hotel = gets.chomp.downcase
puts 'For how many nights?'
days = gets.to_i
cost = if hotel == 'a'
(days / 3) * 500 + (days % 3) * 200
elsif hotel == 'b'
days * 250
elsif hotel == 'c'
(days / 3) * 700 + (days % 3) * 300
elsif hotel == 'd'
days * 500
else
puts 'Unknown hotel.'
end
break if cost
end
puts cost
puts 'Okay...any other hotels? (y/n)'
break unless gets.downcase.start_with?('y')
end
Instead of chained if/elsif/else/end I'd use a case statement:
cost = case hotel
when 'a'
(days / 3) * 500 + (days % 3) * 200
when 'b'
days * 250
when 'c'
(days / 3) * 700 + (days % 3) * 300
when 'd'
days * 500
else
puts 'Unknown hotel.'
end
I am trying to convert a numeric output given by the user so that it always shows 2 decimals. I know that '%.2f' % exists, but it always displays this error "string can't be coerced into fixnum" (I think it conflicts with the methods)
Here's my code:
hash = {}
entry = " "
while entry != "q"
print "Enter your item: "
item = gets.chomp
print "Enter the associated cost: "
cost = gets.chomp.to_f.round(2)
print "Press any key to continue or 'q' to quit: "
entry = gets.chomp
hash[item] = cost
end
puts "Receipt: "
puts "----------"
hash.each do |k,v|
puts "#{k} => $#{v}"
end
puts "----------"
print "subtotal: "
subtotal = hash.values.inject(0, :+)
print "$"
puts '%.2f' % subtotal.round(2)
print "tax: $"
tax = subtotal * 0.06
puts '%.2f' % tax.round(2)
print "total: $"
total = subtotal + tax
puts '%.2f' % total.round(2)
So basically this step:
hash.each do |k,v|
puts "#{k} => $#{v}"
For instance, when I input a cost of 1 in a step before it will show it as
$1.0 and not $1.00
I appreciate any help!
You can do:
hash.each do |k,v|
puts "#{k} => $#{'%.2f' % v}"
end
I'm writing a program which takes input, stores it as a hash and sorts the values.
I'm having trouble comparing a current hash value with a variable.
Sample Input:
3
A 1
B 3
C 5
A 2
B 7
C 2
Sample Output:
A 1 2
B 3 7
C 2 5
Everything works apart from this part, and I'm unsure why.
if values.key?(:keys)
if values[keys] >= val
values.store(keys,val.prepend(val + " "))
else
values.store(keys,val.concat(" " + val))
end
else
values.store(keys,val)
end
i = i + 1
end
Rest of code:
#get amount of records
size = gets.chomp
puts size
size = size.to_i
values = Hash.new(0)
i = 0
while i < (size * 2)
text = gets.chomp
#split string and remove space
keys = text.split[0]
val = text.split[1]
#check if key already exists,
# if current value is greater than new value append new value to end
# else put at beginning of current value
if values.key?(:keys)
if values[keys] >= val
values.store(keys,val.prepend(val + " "))
else
values.store(keys,val.concat(" " + val))
end
else
values.store(keys,val)
end
i = i + 1
end
#sort hash by key
values = values.sort_by { |key, value| key}
#output hash values
values.each{|key, value|
puts "#{key}:#{value}"
}
Could anyone help me out? It would be most appreciated.
The short answer is that there are two mistakes in your code. Here is the fixed version:
if values.key?(keys)
if values[keys] >= val
values.store(keys,values[keys].prepend(val + " "))
else
values.store(keys,values[keys].concat(" " + val))
end
else
values.store(keys,val)
end
The if statement was always evaluating as false, because you were looking for hash key named :keys (which is a Symbol), not the variable you've declared named keys.
Even with that fixed, there was a second hidden bug: You were storing a incorrect new hash value. val.concat(" " + val) would give you results like A 2 2, not A 1 2, since it's using the new value twice, not the original value.
With that said, you code is still very confusing to read... Your variables are size, i, text, val, values, key and keys. It would have been a lot easier to understand with clearer variable names, if nothing else :)
Here is a slightly improved version, without changing the overall structure of your code:
puts "How may variables to loop through?"
result_length = gets.chomp.to_i
result = {}
puts "Enter #{result_length * 2} key-value pairs:"
(result_length * 2).times do
input = gets.chomp
input_key = input.split[0]
input_value = input.split[1]
#check if key already exists,
# if current value is greater than new value append new value to end
# else put at beginning of current value
if result.key?(input_key)
if result[input_key] >= input_value
result[input_key] = "#{input_value} #{result[input_key]}"
else
result[input_key] = "#{result[input_key]} #{input_value}"
end
else
result[input_key] = input_value
end
end
#sort hash by key
result.sort.to_h
#output hash result
result.each{|key, value|
puts "#{key}:#{value}"
}
h = Hash.new { |h,k| h[k] = [] }
input = ['A 1', 'B 3', 'C 5', 'A 2', 'B 7', 'C 2'].join("\n")
input.each_line { |x| h[$1] << $2 if x =~ /^(.*?)\s+(.*?)$/ }
h.keys.sort.each do |k|
puts ([k] + h[k].sort).join(' ')
end
# A 1 2
# B 3 7
# C 2 5
This would be a more Ruby-ish way to write your code :
input = "A 1
B 3
C 5
A 2
B 7
C 2"
input.scan(/[A-Z]+ \d+/)
.map{ |str| str.split(' ') }
.group_by{ |letter, _| letter }
.each do |letter, pairs|
print letter
print ' '
puts pairs.map{ |_, number| number }.sort.join(' ')
end
#=>
# A 1 2
# B 3 7
# C 2 5
print "Enter your age in Numbers:"
user_input = gets.chomp
if user_input > 21 && user_input < 30
puts "XYZ"
elsif user_input > 31 && user_input < 40
puts "YZX"
elsif user_input > 40
puts "ZXY"
else
puts "Golden Age!"
end
The problem is that gets.chomp returns a string
You can convert it to integer by using String#to_i: gets.chomp.to_i
You can further improve the readability of your code by using between?:
print "Enter your age in Numbers:"
number = gets.chomp.to_i
if number.between?(22, 29)
puts "XYZ"
elsif number.between?(32, 39)
puts "YZX"
elsif number > 40
puts "ZXY"
else
puts "Golden Age!"
end
Or even better - a case statement:
print "Enter your age in Numbers:"
number = gets.chomp.to_i
case number
when (22...30) then puts "XYZ"
when (32...40) then puts "YXZ"
when (40..Float::INFINITY) then puts "ZXY"
else puts "Golden Age!"
end
Note: I made the ranges compatible with your original solution, but please note that there are some gaps in there (31 for example).
You can compare objects on which <=> is defined properly, but you cannot compare a string object with a fixnum object. If you intended to compare as an integer, you need to convert the input to integer. Also, (assuming that you only get inputs that can be converted to integers), your condition is redundant. And you are probably using && incorrectly. It can be written like this:
print "Enter your age in Numbers:"
user_input = gets.to_i
if user_input < 20 or [20, 21, 30, 31, 40].include?(user_input)
puts "Golden Age!"
elsif user_input < 30
puts "XYZ"
elsif user_input < 40
puts "YZX"
else
puts "ZXY"
end
I have an Array-1 say
arr1 =['s','a','sd','few','asdw','a','sdfeg']
And a second Array
arr2 = ['s','a','d','f','w']
I want to take arr1 and sort the frequency of letters by inputting arr2 with result
[s=> 4, a=> 2, d => 3] So on and so forth.
As far as I can muddle around.. Nothing below works, Just my thoughts on it?
hashy = Hash.new
print "give me a sentance "
sentance = gets.chomp.downcase.delete!(' ')
bing = sentance.split(//)
#how = sentance.gsub!(/[^a-z)]/, "") #Remove nil result
#chop = how.to_s.split(//).uniq
#hashy << bing.each{|e| how[e] }
#puts how.any? {|e| bing.count(e)}
#puts how, chop
bing.each {|v| hashy.store(v, hashy[v]+1 )}
puts bing
Thank you for your time.
I assumed that you want to count all letters in the sentence you put in, and not array 1. Assuming that, here's my take on it:
hashy = Hash.new()
['s','a','d','f','w'].each {|item| hashy[item.to_sym] = 0}
puts "give me a sentence"
sentence = gets.chomp.downcase.delete!(' ')
sentence_array = []
sentence.each_char do |l|
sentence_array.push(l)
end
hashy.each do |key, value|
puts "this is key: #{key} and value #{hashy[key]}"
sentence_array.each do |letter|
puts "letter: #{letter}"
if letter.to_sym == key
puts "letter #{letter} equals key #{key}"
value = value + 1
hashy[key] = value
puts "value is now #{value}"
end
end
end
puts hashy