Ensure all values in user-input array are between 1 and 10 - ruby

I am trying to define an array based on user input and want to make sure that each value is between 1 and 10. How can I do that?
So I am using this right now.
array = gets.chomp
I want the user to only input values ranging from 1 to 10. How do I do that?

You can just use the below to do that:
def verify(input)
(1..10).to_a.include?(input)
end
#input is user input
if verify(input)
#do some stuff
else
#don't do stuff
end

...So you know, gets.chomp doesn't return an array. It returns a String. Something like this will give you the array you want:
array = gets.chomp.split(/\D/).map { |e| e.to_i }
That converts it from a single string (which happens to contain ,-separated values) to an array of numbers.
puts 'The array you entered was invalid!' if array.any? { |item| !(1..10).include?(item) }
That goes through and checks if any of the values return true for !(1..10).include?(item), which returns true if and only if the range [1,10] (inclusive) contains item. If so, it prints out The array you entered was invalid!.
However, it looks like what you want to do is physically prevent the user from entering a number like 11 or 12 into the console, which (in pure Ruby at least) is impossible. The closest you can get is validating the input after the fact, which is what this does. Look into Ruby's various loops if you want to have them keep entering the array until the array they enter is valid.
Note that #locoboy's answer will work for single numbers, but it will fail when attempting to validate the entire array, or the direct result of gets.chomp.

Related

Last element of the ruby array is nil

I have a simple ruby program that has 2 steps so far
1. Ask the user for the number of stock market symbols they want to track
2. Ask the user to input these symbols
puts("How many stocks do you want to track ?")
numStocks = gets.chomp()
puts("Please enter #{numStocks} stock symbols: ")
array = Array.new(numStocks.to_i)
for i in 1..numStocks.to_i do
array.insert(i-1, gets.chomp())
end
puts("Stock symbols entered ... #{array}")
The output that is printed onto the console is
Stock symbols entered ... ["aapl", nil]
Why is the last element of the array nil in this case and what's the proper way to get rid of it ?
Array.new creates a new array, filling it with the quantity of elements you specified. Array.new(3) is the same as [nil, nil, nil]. Array.new(2, 'a') is the same as ['a', 'a'].
You then use array.insert which adds instead of replaces the elements. You could use array[i-1] = gets.chomp() to set the values, but there's really no reason to initialize the array this way at all.
A "more Ruby" way to write this all would be:
puts 'How many stocks do you want to track ?'
num_stocks = gets.chomp
puts "Please enter #{num_stocks} stock symbols: "
array = 1.upto(num_stocks.to_i).map do
gets.chomp
end
puts "Stock symbols entered ... #{array}"
EDIT:
Also, it’s worth mentioning that in Ruby, arrays are not a fixed size. You can add and remove elements from them as you please. If I had to guess, you’re used to languages like C, where you have to define the size of your array up front and then it’s just that size forever (that’s what I’m guessing you were trying to do anyways).
And another thing, in Ruby it’s not very common to use Array.new. Most times people just define an array by typing an array literal.
array = [1,2,3]
A ruby array is more like a List in other languages. It supports push (though << is a more common method for adding to an array), pop, and other list-like features.
Thats because when you do Array.new(numStocks.to_i) it initializes an array with 3 nil values and you keep adding on to it,
the proper way to get rid of nil from array is to use .compact on the array but I suggest you change your logic,
maybe something like this
puts("How many stocks do you want to track ?")
numStocks = gets.chomp()
puts("Please enter #{numStocks} stock symbols: ")
array = Array.new() # or array = []
numStocks.to_i.times do
array << gets.chomp()
end
puts("Stock symbols entered ... #{array}")
or you could ask the user to enter the comma separated symbols, so you don't have to loop, and split them,
puts("Please enter #{numStocks} stock symbols separated by commas (a,b): ")
symbols = gets.chomp().split(',')
puts("Stock symbols entered ... #{array}")

Guessing game for ruby

I'm currently trying to create a simply made guessing game, In the code there will be three set number (for now) that a person has to guess. If he/she guesses all the numbers correctly it puts, "Congrats, you win!"
Now as a beginning test i just wanted the user to guess one number correctly and the code gives back correct or incorrect.
random_guess = [1, 3, 5]
puts "Please Pick a number, 1-5"
pick_num = gets.chomp
if pick_num == random_guess = true
puts "Correct!"
else
puts "Incorrect!"
end
(I know this code is very beginner, i'm very new to ruby.) for some reason every time i run this program it puts incorrect.
Your if statement is wrong. It should be:
if random_guess.include? pick_num.to_i
Note that if you leave off the to_i the equality check will always fail because you're comparing the integer 3 against the string "3".
Just to help you a bit more. Since your end goal is to have the user guess all the numbers correctly. You can just loop on the same if statement I wrote above. And every time they guess a correct number you can remove it from the array like such:
random_guess.delete(pick_num.to_i)
Once the array is empty, the user has won.
Making random_guess random:
random_guess = []
3.times{random_guess << rand(1..5)}
random_guess
# => [5, 1, 4] # will be random in every other iteration
Checking if the number exists, you can either use index or include?:
if random_guess.index(pick_num.to_i) # alternatively random_guess.index(pick_num.to_i)
puts "Correct!"
else
puts "Incorrect!"
end
Why is your code always printing incorrect?
You are doing if pick_num == random_guess = true, which is a blunder. What is actually happening here is:
you are assigning true to random_guess. i.e. irrespective to what value (Array) random_guess holds, you are overwriting it with true.
Then you are comparing random_guess with pick_num.
So essentially you are doing this:
if pick_num == (random_guess = true) # say pick_num = "1"
# "1" == true # which is obviously false.
The correct conditional statement should be:
if pick_num == random_guess
However this will also print false every time. Reason?
pick_num is a string.
random_guess is an array that contains integer values.
You are comparing two different object types. So its always false.
Therefore the right way to solve this is checking whether the user entered value exists in the Array. For that you can use Array#index or Array#include?. Hence the statement in my proposed solution:
if random_guess.index(pick_num.to_i)
NOTE: pick_num.to_i converts pick_num (a character) into an integer. This is required as your array contains only integers and not characters.

Max value of nested array in hash

What I have:
hash = {id =>[string, number], id =>[string, number]}
I need to get the max value of number. I have been able to do this, but when I puts it.
I get:
id
string
number
What I need please
id string number
This is what I've tried:
This brings the max value to the top of list, but I need to exclude the rest of the list.
hash.each{|x, y| puts "#{x} #{y[0]} #{y[1]}"}.max
This returns the max value but displays it vertically
puts hash.max_by{|y| "#{y}"}
I have tried numerous other things and am having a hard time wrapping my head around this one.
Not sure if it matters but I am read this in from a file into a hash, the number is a float
The max here doesn’t do anything (since it is called on hash and its return value never used):
hash.each{|x, y| puts "#{x} #{y[0]} #{y[1]}"}.max
This is the same as doing puts on an array (since that’s what max_by returns), which prints each element on a separate line. You’re also unnecessarily converting your number to a string (which can result in unexpected comparison results):
puts hash.max_by{|y| "#{y}"}
Instead let’s just get the max key/value pair:
max = hash.max_by { |id, (string, number)| number }
#=> ["the-id", ["the-string", 3.14]]
Now we can flatten and join the array before puts-ing it:
puts max.flatten.join(' ')
# prints: the-id the-string 3.14
I would re-arrange the hash with number as the key, then use sort_by(): http://www.rubyinside.com/how-to/ruby-sort-hash

Ruby how does this inject code work?

I am new to Ruby and I am trying to write a method that groups an array of words into anagram groups. Here is the code:
def combine_anagrams(words)
dict = words.inject(Hash.new(0)) do |list,ws|
key = sort_word(ws)
if !list.has_key?(key)
list[key] = []
end
list[key].push(ws)
list #What is this
end
return dict.values
end
My question is what the statement list is for. If I take it out list becomes an array instead of hash.
Every method/block/etc. in Ruby returns something, and unless there is an early return statement, whatever the last statement in the method/block/etc. is, is what is returned.
In your case, having list be the last line in the block passed to inject ensures that list is returned by the block. When you remove it, the return value of list[key].push(ws) is returned, which obviously isn't what you want.
Note that this behavior also makes using the return keyword when it is the last statement that would be executed otherwise is unnecessary (this includes the return you have at the end of your method). Though some prefer to be explicit that they intend to return something and use them even when not needed.
On an unrelated note: your if !list.has_key?(key) can be rewritten unless list.has_key?(key).
inject works like this:
final = enumerable.inject(initial_value) do |current_value, iteration|
# calculations, etc. here
value # next iteration, current_value will be whatever the block returns
end
So, in your case, initial_value is Hash.new(0), or an empty Hash with 0 as the default value for a key that doesn't exist instead of nil. This is passed into the inject block for the first element in enumerable.
Inside the inject block, you check to see if key already exists as a key on the hash. If it does not, set it equal to an empty array. In either case, take the current iteration of words (ws) and push it onto the array.
Finally, the block returns the current version of list; it becomes current_value (the first parameter to the inject block) the next time the loop processes an element from enumerable.
As a more simple example, check out this sample:
numbers = [1, 2, 3, 4]
sum = inject(0) do |total, number| # first time, total will be 0
total + number # set total next time to be whatever total is now plus the current number
end
Take a look at http://ruby-doc.org/core-1.9.3/Enumerable.html#method-i-inject
In the inject method if you pass two arguments into it (in your case list and ws) the first one - list - is so-called accumulator value. The value which is returned by the inject block at each iteration step is assigned to the list variable. So the line with the only word "list" which you commented as "#What is this" is used for assigning the value of the list in the block to the "list" accumulator variable.
the statement "list" is the return value of the whole block. The line: "list[key] = []" has a return value of "list", therefore it doesnt need another line to set the return value of the if condition to 'list', but the return value of list[key].push(ws) is list[key]. we want to get the updated value of list in the end, therefore we need to return that value from the block each time, so that further processing acts of the updated list, and not something else.
As a background, each ruby line also has a return value, so if that were the last line of a block, or a function, it automatically becomes the return value of the whole block or the function respectively.
To understand this further, try some code like this in irb:
a = [1,2,3,4,5]
b = a.inject(0) {|sum, val| puts sum; puts val; sum + val}
the inner block comprises of three statememts; the last statement returns the value of sum+val to the block, which get stored in sum, to be used in next iterations.
Also, try some code like this:
h = {:a => []}
b = h[:a].push 6
See what b evaluates to; in your code, you need 'b' to be the accumulated hash, and not the array that is stored in h[:a]

How do I search for a chunk of text and pull an element that matches out of a hash in Ruby?

I have a hash filled with 32 strings of the names and locations of NFL teams (e.g. "Baltimore Ravens", "Pittsburgh Steelers," etc.)
I'm writing a class called def search which asks the user to enter the name of a team and then runs a while loop that looks through the hash, tries to match the user inputted string with a piece of a string in the hash and return the full value.
For example, if you enter Ravens, it should return "Baltimore Ravens"
I'm not sure of the correct things to enter in my code to take the piece of the string entered and try to match it with the full string and return a result. Googling hasn't helped answer my question so I'm turning to you great people.
Thanks in advance for your help.
Real code:
def search(team, nfl)
favTeam = nfl.find_all { |i| i = team }
puts favTeam
end
That's printing all of the teams in the nfl Array (not a Hash, I made a mistake). Not entirely sure what I'm supposed to write to make it look for team (which is what the user has already inputted) to compare it to the values in the array.
Given your hash in h and the substring you're looking for in s:
key = h.detect { |k, v| v.downcase.index(s.downcase) }.to_a.first
will give you the first key in h whose value contains s (case insensitive). The to_a call is just a simple way to convert a possible nil return to an empty array without requiring an extra check.
If you wanted them all, then:
keys = h.find_all { |k, v| v.downcase.index(s.downcase) }.map(&:first)
You might want to downcase s before the iteration but it won't matter much for only 32 values.
References:
detect (AKA find)
find_all (AKA select)
Updates to match the updated question: Since you actually have an array instead of a hash:
matches = nfl.find_all { |name| name.downcase.index(team.downcase) }
You'd still use find_all (or select if you like that name better), just adjust the block argument to match what find_all on an Array gives you.

Resources