How should I setup this if and else statement? [duplicate] - ruby

This question already has answers here:
Array that alphabetizes and alternates between all caps
(5 answers)
Closed 7 years ago.
Without changing any of the other code- What can I put into my if else statement to make array 0, 2, 4 show up as all capital letters? I can't figure out how to assign this within the if and else statement.
test = []
puts "Please type 5 different words when you're ready-"
5.times do
test << gets.chomp
end
test.sort.each do |user|
if #what could I put in this statement for all capital letters on [0,2,4]?
user.upcase
else #.downcase isn't needed, if its simpler to remove it that is fine
user.downcase
end
end

I think what you need to do is change the each loop to each_with_index. The each_with_index loop should get what you need.
test.sort.each_with_index do |user, index|
if ([0,2,4]include? index)
user.upcase
else
user.downcase
end
end
If the array is going to expand, you could use the #even? method on the index as the check in the if statement like so.
test.sort.each_with_index do |user, index|
if (index.even?)
user.upcase
else
user.downcase
end
end
If you can't change the type of loop then you could use the #index method on the array, to tell you where the user is in the test array like so
test.sort.each do |user|
if ([0,2,4].include? (test.sort.index(user)))
user.upcase
else
user.downcase
end
end

Why without changing any of the other code? Just do this, no one will care:
puts "Please type 5 different words when you're ready-"
5.times.map { |i| i.even? ? gets.chomp.downcase : gets.chomp.upcase }
The times loop autoindexes for this reason, and the ternary operator (?:) is built for this case.

Related

Making a sorted array of user's input

I'm learning Ruby with 'Learn to Program' by Chris Pine. On chapter 10 I should write a program where the user types as many words as he like and when he's done, he can just press Enter on an empty line and exit.
I came up with this:
puts "Type whatever you want!"
index = 0
word = ''
array = []
while word != nil
word << gets.chomp
array[index] = word
index = index + 1
end
puts ''
puts array.sort
But that doesn't work. What did I miss? Is there another way I could define word without having to repeat it?
The word will not have nil value. It will be an empty string. So you need to check for that:
while word != ""
# or even better
while !word.empty?
Also, you are adding everything to your word. You probably want to assign to it instead:
word = gets.chomp
Per author's comment:
begin
# your code here
end while !word.empty?
# OR more readable
begin
# your code here
end until word.empty?
It seems like there's a simpler solution, if I'm reading the question correctly.
You could do something like this:
user_input = gets.chomp.split(" ").sort
ex)
input: bananas clementine zebra tree house plane mine
output: ["bananas", "clementine", "house", "mine", "plane", "tree", "zebra"]
Here's a simple loop that you could do just for kicks:
arr = []
arr << $_.strip until gets =~ /^\s*$/
puts arr.sort
$_ is a special variable that evaluates to the last input read from STDIN. So basically this reads "Call gets and check if the input is just spaces. If it is then break out of the loop, otherwise append the last input with whitespace removed value onto the array and continue looping."
Or even more fun, a one liner:
puts [].tap {|arr| arr << $_.strip until gets =~ /^\s*$/}.sort
Basically same thing as above except using tap to initialize the variable.
To answer your questions:
Is there another way I could define word without having to repeat it?
Use side effects of assignment. In ruby when you assign a variable the return value of that assignment is the assigned variable, as in:
irb(main):001:0> (variable = 2) == 2
=> true
The idea would be to put the assignment in the your conditional. If I were to write something like this in a comprehensible loop, as opposed to those above, I'd write something like this:
arr = []
while !(word = gets.strip).empty?
arr << word
end
puts arr.sort
Using loop might simplify the code:
a = []
loop do
input = gets.chomp
if input.empty?
break
else
a << input
end
end
a.sort!
puts a

Able to use a variable within another variable's name? Ruby

So my goal is to be able to run through a "while" loop and in each iteration create a new variable that includes the "iteration count" within that variables name and stores it for later use outside of the loop. See below for more details.
NOTE: The code is clearly wrong in so many ways but I'm writing it this way to make it more clear? as to what I am trying to accomplish. Thanks for any input on how this is possible.
count = "4"
while count > "0"
player"#{count}"_roll = rand(20)
puts 'Player "#{count}" rolled: "#{player"#{count}"_roll}"'
count -= 1
end
My goal is then to be able to access the variables that were created from within the loop at a later part of the program like so (more or less)
puts player4_roll
puts player3_roll
puts player2_roll
puts player1_roll
The key being that these variables were A) created in the loop B) With names relying on another variables input, and C) accessible outside the loop for later use.
Hopefully my question came out clear and any input will be greatly appreciated. I'm very new to programming and trying to get my head wrapped around some more complex ideas. I'm not sure if this is even possible to do in Ruby. Thanks!
I think the best way is to use arrays or hashes, with arrays its something like this:
count = 0
array = []
while count < 4 do
array[count] = rand(20)
puts "Player #{count} rolled: #{array[count]}"
count += 1
end
array.each do |var|
puts var
end
You store the result in the array and then you loop trough it. If you want the result of the second iteration of the loop you do something like this:
puts array[1]
If you want to use Hashes there are some modifications you need to do:
count = 0
hash = {}
while count < 4 do
hash["player#{count}_roll"] = rand(20)
puts "Player #{count} rolled: #{hash["player#{count}_roll"]}"
count += 1
end
hash.each do |key, var|
puts var
end
If you want the result of the second iteration of the loop you do something like this:
puts hash["player1_roll"]
You could set the variable using instance_variable_set and reference it that way
instance_variable_set("#player#{count}_roll", rand(20))

Checking if content of an array is all integers [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I'm working on a sorting code. I would like to check if my array contains non integers. Here is my code:
array = Array.new
puts "Please enter your 3 digits."
3.times do
str = gets.chomp.to_i
array.push str.to_i
end
if array.is_a?(Numeric) == false
puts "Error, only use Integers please!"
else
print "Here are your sorted numbers: #{array.sort}"
end
You clearly can't gets.chomp.to_i (or the equivalent, gets.to_i), because that will only return integers. You therefore need to see if the string represents a number before adding it to the array.
You can do that with a regular expression or confirm that Kernel::Integer does not raise an exception (and catch it if it does).
A regular expression that would work is simply:
str =~ /^-?\d+$/
after
str = gets.chomp.strip
To use Kernel::Integer:
def integer?(str)
begin
Integer(str)
rescue ArgumentError
return false
end
str.to_i
end
For example,
integer?("-33") #=> -33
integer?("-x33") #=> false
integer?(" 33 ") #=> 33
integer?("33\n") #=> 33
The last two examples show that you can drop chomp.strip from gets.chomp.strip when using this approach.
If you wish to allow integers or floats, change the regular expression to:
/^-?\d+\.?\d*$/
or check to see that Kernel::Float raises an exception:
def float?(str)
begin
Float(str)
rescue ArgumentError
return false
end
str.to_f
end
float?("-33.4") #=> -33.4
float?("-33") #=> -33.0
float?("x33.4") #=> false
float?(" 33.4\n") #=> 33.4
With the code you have above your array is guaranteed to contain integers since you are converting your input to Integers using to_i:
array.push str.to_i
You are in fact doing it twice. When you read the string from STDIN and when you push it onto the array.
You need to check to see if the input is a string before you call to_i.
3.times do
str = gets.chomp
# code to verify if str is numeric.
array.push str
end
There are lots of ways to implement that code depending on what your requirements are. Integers only could be done like this:
unless str =~ /^\d+$/
puts "Error, only use Integers please!"
exit
end
The above would work for any positive integers, but not negative. It would also fail if you allowed decimals. But it gives you an idea. Search "ruby check if string is a number" and you'll find a lot more info.
Also note that the above fails as soon as it finds a non integer instead of waiting till after.

Catch and throw not working in ruby

I am trying to make a number guessing game in Ruby but the program exits after I type in yes when I want to play again. I tried using the catch and throw but it would not work. Could I please get some help.
Here is my code.
class Game
def Play
catch (:start) do
$a=rand(11)
puts ($a)
until $g==$a
puts "Guess the number between 0-10."
$g=gets.to_i
if $g>$a
puts "The number you guessed is too high."
elsif $g==$a
puts "Correct you won!!!"
puts "Would you like to play again?"
$s=gets()
if $s=="yes"
$c=true
end
if $c==true
throw (:start)
end
elsif $g<$a
puts "The number you guessed is too low."
end
end
end
end
end
Game.new.Play
Edit: Here's my new code after trying suggestions:
class Game
def Play
catch (:start) do
$a=rand(11)
puts ($a)
while $s=="yes"
until $g==$a
puts "Guess the number between 0-10."
$g=gets.chomp.to_i
if $g>$a
puts "The number you guessed is too high."
elsif $g==$a
puts "Correct you won!!!"
puts "Would you like to play again?"
$s=gets.chomp
if $s=="yes"
throw (:start)
end
elsif $g<$a
puts "The number you guessed is too low."
end
end
end
end
end
end
Game.new.Play
Your first problem is here:
$s=gets()
if $s=="yes"
$c=true
end
The gets method will read the next line including the new line character '\n', and you compare it to only "yes":
> gets
=> "yes\n"
The idiomatic way to fix this in Ruby is the chomp method:
> gets.chomp
=> "yes"
That said, your code has two other deficiencies.
You may come from a language such as PHP, Perl, or even just Bash scripting, but Ruby doesn't require the dollar sign before variables. Using a $ gives a variable global scope, which is likely not what you want. In fact, you almost never want a variable to have global scope.
Ruby uses three types of symbol prefixes to indicate scope - # for instance, ## for class, and $ for global. However the most common type of variable is just local which doesn't need any prefix, and what I would suggest for your code.
I have always been told that it is very bad practice to use exceptions for control structure. Your code would be better served with a while/break structure.
When you do gets(), it retrieves the full line with a '\n' in the end. You need to trim the new line character by using:
$g=gets.chomp.to_i
Same for other gets
Based on your updated code (where you fixed the newline problem shown by others), your new problem is that you have wrapped all your game inside while $s=="true". The very first time your code is run, $s is nil (it has never been set), and so you never get to play. If you used local variables instead of global variables (s instead of $s) this would have become more obvious, because the code would not even have run.
Here's one working way that I would re-write your game.
class Game
def play
keep_playing = true
while keep_playing
answer = rand(11) # Make a new answer each time
puts answer if $DEBUG # we don't normally let the user cheat
loop do # keep going until I break from the loop
puts "Guess the number between 0-10."
guess = gets.to_i # no need for chomp here
if guess>answer
puts "The number you guessed is too high."
elsif guess<answer
puts "The number you guessed is too low."
else
puts "Correct you won!!!",
"Would you like to play again?"
keep_playing = gets.chomp.downcase=="yes"
break
end
end
end
end
end
Game.new.play
I know this doesn't really answer your question about why your code isn't working, but after seeing the code you posted I just had to refactor it. Here you go:
class Game
def initialize
#answer = rand(11)
end
def play
loop do
guess = get_guess
display_feedback guess
break if guess == #answer
end
end
def self.play_loop
loop do
Game.new.play
break unless play_again?
end
end
private
def get_guess
puts "Guess the number between 0-10."
return gets.chomp.to_i
end
def display_feedback(guess)
if guess > #answer
puts "The number you guessed is too high."
elsif guess < #answer
puts "The number you guessed is too low."
elsif guess == #answer
puts "Correct you won!!!"
end
end
def self.play_again?
puts "Would you like to play again?"
return gets.chomp == "yes"
end
end
Game.play_loop

Syntax for a for loop in ruby

How do I do this type of for loop in Ruby?
for(int i=0; i<array.length; i++) {
}
array.each do |element|
element.do_stuff
end
or
for element in array do
element.do_stuff
end
If you need index, you can use this:
array.each_with_index do |element,index|
element.do_stuff(index)
end
limit = array.length;
for counter in 0..limit
--- make some actions ---
end
the other way to do that is the following
3.times do |n|
puts n;
end
thats will print 0, 1, 2, so could be used like array iterator also
Think that variant better fit to the author's needs
I keep hitting this as a top link for google "ruby for loop", so I wanted to add a solution for loops where the step wasn't simply '1'. For these cases, you can use the 'step' method that exists on Numerics and Date objects. I think this is a close approximation for a 'for' loop.
start = Date.new(2013,06,30)
stop = Date.new(2011,06,30)
# step back in time over two years, one week at a time
start.step(stop, -7).each do |d|
puts d
end
The equivalence would be
for i in (0...array.size)
end
or
(0...array.size).each do |i|
end
or
i = 0
while i < array.size do
array[i]
i = i + 1 # where you may freely set i to any value
end
array.each_index do |i|
...
end
It's not very Rubyish, but it's the best way to do the for loop from question in Ruby
To iterate a loop a fixed number of times, try:
n.times do
#Something to be done n times
end
If you don't need to access your array, (just a simple for loop) you can use upto or each :
Upto:
2.upto(4) {|i| puts i}
2
3
4
Each:
(2..4).each {|i| puts i}
2
3
4
What? From 2010 and nobody mentioned Ruby has a fine for /in loop (it's just nobody uses it):
ar = [1,2,3,4,5,6]
for item in ar
puts item
end
['foo', 'bar', 'baz'].each_with_index {|j, i| puts "#{i} #{j}"}
Ruby's enumeration loop syntax is different:
collection.each do |item|
...
end
This reads as "a call to the 'each' method of the array object instance 'collection' that takes block with 'blockargument' as argument". The block syntax in Ruby is 'do ... end' or '{ ... }' for single line statements.
The block argument '|item|' is optional but if provided, the first argument automatically represents the looped enumerated item.

Resources