Multiple conditions in a "While" loop Ruby - ruby

I'm creating an app that tells what month of the year each number from 1 to 12 represents, like 1 = January, 2 = February, etc. This is the initial code
print "Please, tell me the month's number!"
number = gets.chomp.to_i
while number > 12 do
print "Please, re-type it again!"
number = gets.chomp.to_i
end
case number
when 1 then print "This is January!"
when 2 then print "This is February!"
when 3 then print "This is March!"
when 4 then print "This is April!"
when 5 then print "This is May!"
when 6 then print "This is June!"
when 7 then print "This is July!"
when 8 then print "This is August!"
when 9 then print "This is September!"
when 10 then print "This is October!"
when 11 then print "This is November!"
when 12 then print "This is December!"
else print "I can't undestand you, i'm sorry!"
end
Now, the basic logic is set. The only thing that I think is missing is the second condition in the while loop that defines that, if the input isn't an integer, I need to retype it. I'm trying to define the second condition in that while loop correctly, but no results so far. How can I do it?
How can I make the code better? And is the while loop in this context the right method for the job?

Here is another way to make your code better:
require 'date'
print "Please, tell me the month's number! "
number = gets.to_i
until number.between?(1,12) do
print "Please, re-type it again! "
number = gets.to_i
end
month_name = Hash.new
(1..12).each do |month_num|
month_name[month_num] = Date::MONTHNAMES[month_num]
end
print "This is #{month_name[number]}!"
As noted in other answers chomp is not necessary if using to_i because converting to an integer will take care of the new line.
I am using number.between?(1,12) as suggested by #steenslag to check if the input is valid.
I tried a Hash approach instead of the case statement. A while loop is one way to do this but this is just one other way to get it done.

print "Please, tell me the month's number!"
number = gets.to_i
You never need chomp if you are going to use to_i because the very nature of a number states that it will never have a line ending.
until number > 1 && number < 12 do
You do want the number to be inclusive of 1 to 12, right?
You could alternative do this,
until (1..12).include?(number) do
Or as #teenslag states,
until number.between?(1, 12) do
I think either reads easier, and between? method may be the better choice.
print "Please, re-type it again!"
number = gets.to_i
end
This can be very DRY, or using the built in Date object, as mentioned. But let's see what we can do with the code as you have it, in the same spirit:
case number
when 1 then print "This is January!"
when 2 then print "This is February!"
when 3 then print "This is March!"
when 4 then print "This is April!"
when 5 then print "This is May!"
when 6 then print "This is June!"
when 7 then print "This is July!"
when 8 then print "This is August!"
when 9 then print "This is September!"
when 10 then print "This is October!"
when 11 then print "This is November!"
when 12 then print "This is December!"
end
turns to this:
answer = case number
when 1
"January"
when 2
"February"
when 3
"March"
when 4
"April"
when 5
"May"
when 6
"June"
when 7
"July"
when 8
"August"
when 9
"September"
when 10
"October"
when 11
"November"
when 12
"December"
end
print "This is #{answer}!"
Though it would be nicer just using the Date class.
If that wasn't available for you, then perhaps I would consider using a Hash here instead. I will let you explore those options.
Or even an Array. Remembering that Array elements start at position 0:
print "Please, tell me the month's number!"
until (number = gets.to_i).between?(1,12) do
print "Please, re-type it again!"
end
months = %w[January February March April May June July August September October November December]
puts "This is #{months[number - 1]}!"

number will always be an integer because you converted it into an integer.
"foo".to_i
=> 0
You probably want to use a range instead.
until (1..12).include?(gets.chomp.to_i)
print "Please, re-type it again!"
end
You can also DRY your code by using the built-in number to month conversion:
number = 4
Date::MONTHNAMES[number]
=> "April"

As the above posters have mentioned, this particular instance does not require a second condition. However, in the event you need a multiple condition while loop you would use the logical AND or the logical OR operator.
The logical AND operator is &&. The logical OR operator is ||. You would use && if both conditions need to be true to continue the loop. You'd use the || if one or the other would need to be true to continue the loop.
For example:
while number > 12 || number == 0 do
stuff...
end
while number > 0 && number < 13 do
stuff...
end
In the first snippet, you will enter the loop if the number entered is either above 12 OR equal to 0. In the second you will enter the loop if the number entered is greater than 0 AND less than 13. (Obviously, the second one would be exactly the opposite of what you were using the while loop for here, but is included for demonstration).

A simple loop that you need:
until month_num > 0 && month_num < 13 do
# prompt again
end
A more idiomatic way would be to use between? or include?
until month_num.between? (1, 12) do
# prompt again
end
And instead of multiple when then, you could use a hash map from the Date module:- Date::MONTHNAMES[month_num]

Related

Ruby Countdown loop Learn Lab

I am currently working on a lab to create a countdown timer using a while loop and the subtract/assign operator. So far I have the loop counting 10 and breaking to 0 and printing my string "Happy New Year". I am not sure why it isn't iterating from 10 down to 0. Link to lab and code below https://learn.co/tracks/online-software-engineering-structured/procedural-ruby/looping/countdown-to-midnight-lab
number = 10
while number > 0
puts "#{number} SECOND(S)!"
number -= 1
break if n <= 0
puts "HAPPY NEW YEAR!"
end
end
There is one end too much. Proper indentation could have told you that.
puts "HAPPY NEW YEAR!" should probably be the last line, out of the loop (and probably without the puts).
n should be number
The task is in the form of a method which returns a string . puts however returns nil.

How do I display the largest number in an array in Ruby? [duplicate]

This question already has answers here:
How to find a min/max with Ruby
(5 answers)
Closed 4 years ago.
I have a homework assignment that I need to finish. I think most of the code is working but I am having trouble with the last part. I need to display the largest number that a user enters (into an array). Below is the code I have so far. I am open to any suggestions. Thanks in advance.
Here's the description of the assignment:
Write a Ruby application that allows a user to input a series of 10 integers and determines and prints the largest integer. Your program should use at least the following three variables:
a) counter: A counter to count to 10 (i.e., to keep track of how many numbers have been input and to determine when all 10 numbers have been processed).
b) number: The integer most recently input by the user.
c) largest: The largest number found so far.
class Screen
def cls
puts ("\n")
puts "\a"
end
def pause
STDIN.gets
end
end
class Script
def display_instructions
Console_Screen.cls
print "This script will take the user input of 10 integers and then
will
print the largest."
print "\n\nPress enter to continue."
Console_Screen.cls
Console_Screen.pause
end
def getNumber #accepts user input
list = Array.new
10.times do
Console_Screen.cls
print "This script accepts 10 integers."
print "\n\nPlease type an integer and press enter."
input = STDIN.gets
input.chop!
list.push(input)
end
end
def display_largest(number) #displays the largest integer entered by the
user
Console_Screen.cls
print "The largest integer is " +
end
def runScript
number = getNumber
Console_Screen.cls
display_largest(number)
end
end
#Main Script Logic
Console_Screen = Screen.new
LargestNum = Script.new
answer = ""
loop do
Console_Screen.cls
print "Are you ready to start the script? (y/n): "
print "\n\nWould you like instructions on how this script works? (h): "
answer = STDIN.gets
answer.chop!
break if answer =~ /y|n|h/i
end
if answer == "h" or answer == "H"
LargestNum.display_instructions
print "Are you ready to start the script? (y/n): "
answer = STDIN.gets
answer.chop!
end
if answer == "n" or answer == "N"
Console_Screen.cls
puts "Okay, maybe another time.\n\n"
Console_Screen.pause
else
loop do
LargestNum.runScript
print "\n\nEnter Q to quit or press any key to run the script again: "
runAgain = STDIN.gets
runAgain.chop!
break if runAgain =~ /Q/i
end
end
This question has been asked and answered so many times before. Personally I think, as this answer suggests, the built in .max is the best solution.
[1, 3, 5].max #=> 5
Have you learned about for loops yet? You have to iterate through the array. For a very trivial example, you can do something like
max = 0
for element in list
if element > max
max= element
return max

Generate largest number of 10 inputs

New to scripting here. Basically, I am needing to write a program to accept 10 input numbers and return the largest in the list.
I have this code, but obviously it is not running:
class Generator
def getNumbers
number = Array.new
puts "To begin, You will need to enter your numbers."
print "Press Enter to continue."
Console_Screen.pause
10.times do
print "\nPlease enter any number: "
input = STDIN.gets
input.chop!
list.push
return list
end
list.push(number)
print list.max
end
end
Console_Screen.new
Find = Generator.new
end
Can anyone help me with what I coded incorrectly?
There are many problems with your code. Among them I may point:
1) You created an array named number to store your numbers and then tried to push them to another variable named list;
2) As #tadman pointed, you used a return inside a times block and this makes the block to be executed only once;
3) You never invoked getNumbers to make your process really happen!
This code would do what you need:
class Generator
def get_numbers
numbers = Array.new
puts "To begin, You will need to enter your numbers."
puts
10.times do
print "\nPlease enter any number: "
input = STDIN.gets
input.chop!
numbers.push(input.to_i)
end
print numbers.max
end
end
Find = Generator.new
Find.get_numbers
Notice that I changed the name of your method from getNumbers to get_numbers, which is much more Ruby-like.
Notice that I also changed the name of your array from number to numbers, 'cause it will store numbers, not a single number. Naming your varables correctly may help you to think correctly about your problem. It also helps when it comes for other people reading your program. Even you, six months later, will have problems to understand your own code if you don't name things correctly an comment you code well.
By the way, I also pushed the numbers to numbers as integer, using #to_i. This will make the numbers be compared as numbers, not as strings. If you researsh a bit you'll find out this could be a bit different. If someone enters 0300 as a number, it will be considered to be smaller then 200 as string, but when converted to integers, they will be in the correct order.
Consider this approach perhaps:
#script.rb
nums = []
10.times do |c|
puts "enter number #{c+1}"
nums << gets.to_i
end
puts "max number is #{nums.max}"
Example
$ ruby script.rb
enter number 1
#5
enter number 2
#3
enter number 3
#66
enter number 4
#4
enter number 5
#3
enter number 6
#2
enter number 7
#1
enter number 8
#6
enter number 9
#9
enter number 10
#0
#max number is 66
I had the same assignment and this is what I ended up creating. (I had to get a little more involved with input control and I'm sure there's easier ways of doing this. Also had to utilize the variables as part of the grade. I assume to prevent me from ripping off the code above.)
class Screen
def cls
puts ("\n" * 25)
puts "\a"
end
def pause
STDIN.gets
end
end
Console_Screen = Screen.new
num = [] #array to store user input
$counter = 1
loop do
puts "Please enter number " + $counter.to_s + " of a series of 10 numbers in order to determine the largest."
# Console_Screen.pause
loop do
print "Enter Number Here:"
number = gets.chomp
num << number.to_i if number =~ /[0-9]/ #only writes to the array if it's a number
break if number =~ /[0-9]/ #only allow numbers
end
$counter += 1
break if $counter == 11
end
puts "Press Enter to have your numbers sorted and the largest presented to you."
Console_Screen.pause
largest = num.max
puts "This is your largest number: " + largest.to_s
Console_Screen.pause

re-try logic in a simple loop

I'm trying to set bounds for an array that will later be printed in the console and summed. The lower bound ($a) should be less than 50 and I wrote this code to evaluate for that, but I want it to re-prompt for a number if a higher number is typed. So far, Google and experimentation have failed me.
def num_a
print "Pick a number from 1 to 50: "
$a = Integer(gets.chomp)
until $a < 50
puts "Um, try again please."
# need something here to prompt for another response
# until $a is less than 50
end
end
You could restructure the loop so that the prompt and call to gets are both inside it:
def num_a
# start with a number that doesn't meet the condition
a = 50
# check if the number meets the condition yet
until a < 50
# ask the user to enter a number
print "Pick a number from 1 to 50: "
a = Integer(gets.chomp)
# ask to try again if the number isn't under 50
puts "Um, try again please." unless a < 50
end
# return the entered value to the caller
a
end
Also, as I've shown in the example, I would recommend avoiding the use of global variables ($a in this case).

Ruby if/elseif coding error

I'm writing a simple and small program in Ruby to output the ordinal of a number based on user input. Here is what I wrote:
puts "Enter a number"
number = gets.chomp.to_i
conversion = number % 10
if number == 11 || number == 12 || number == 13
puts "That is #{number}th"
end
if conversion == 1
puts "That is #{number}st"
elsif conversion == 2
puts "That is #{number}nd"
elsif conversion == 3
puts "That is #{number}rd"
else
puts "That is #{number}th"
end
As my code shows, I wanted to take the "number" from the user input, cut off the last number, and use that single digit number to determine whether "number" should be a (fir)st, (seco)nd, (thi)rd, or (four)th type of ordinal. The "conversion" value should convert that for me. However, it can be seen that the numbers 11, 12, and 13 are exceptions. My program works fine except that when I input one of these three values, I get two outcomes, not one, in the terminal such as:
That is 11st
That is 11th
My intention is that "11th" should be displayed, not "11st". Even though I tried to write an exception into my code, the "conversion" still gets executed. I'm not sure what error I made, but is there a way I can isolate the first if statement, so that my conversion does not include 11, 12, and 13?
That is exactly how you have the program written!
If the number is 11,12,13 it will trigger the first if statement, as you expect it to. It will then go to the next if statement because it doesn't have any reason to end. puts is not a return/break statement (a return/break statement would break this code, but that is a different problem) so code will continue to run until the end.
The easiest solution would be to simply combine the two if statements into your main if/else statement:
if number == 11 || number == 12 || number == 13
puts "That is #{number}th"
elsif conversion == 1
puts "That is #{number}st"
elsif conversion == 2
puts "That is #{number}nd"
elsif conversion == 3
puts "That is #{number}rd"
else
puts "That is #{number}th"
end
This will prevent any number from being able to be true in different if loops.

Resources