Reputation: 21
Context: just started learning Ruby, the code below is a part of a slightly longer program, but I only need some help with the first part, and I may not articulate my problem clearly enough, so apologies in advance
Question: I've marked the problem parts of the program. If I have a hash with strings and I want the if-else statement to identify user input, regardless of how a user enters the movie title (e.g. different spacing, capitalization, or without quotation marks) as the same as those in the hash and output the else statement, how would I go about doing that? Thank you
movies = {
"Lord of the Rings" => 4, # <= this
Inception: 4,
"Hurt Locker" => 3.5, # <= this
Mother: 4
}
puts "What would you like to do?"
puts "-- Type 'add' to add a movie."
puts "-- Type 'update' to update a movie."
puts "-- Type 'display' to display a movie."
puts "-- Type 'delete' to delete a movie."
choice = gets.chomp
case choice
when "add"
puts "What movie would you like to add? "
title = gets.chomp
if movies[title.to_sym].nil?
puts "What rating does the movie have? "
rating = gets.chomp
movies[title.to_sym] = rating.to_i
else
# and this
# v
puts "That movie already exists! Its rating is #{movies[title.to_sym]}."
end
end
Upvotes: 1
Views: 128
Reputation: 30131
You have a hash with strings and symbols:
{
"Lord of the Rings" => 4, # <= string
Inception: 4 # <= symbol
}
# NOTE: it is the same as this
{
"Lord of the Rings" => 4, # <= string
:Inception => 4 # <= symbol
}
Because user input is a string, changing the original hash keys to be only strings from the start, seems like the right thing to do.
movies = {
"Lord of the Rings" => 4,
"Inception" => 4,
"Hurt Locker" => 3.5,
"Mother" => 4
}
Users can't be trusted to do the most basic things, like typing the thing they see on the screen. So, some input processing need to happen:
def normalize_string something
something
.to_s # make sure it's a string
.downcase # make everything a lowercase
.gsub(/[^[:alnum:]]/,'') # remove anything but letters and numbers
end
This function can be used like this:
movies = {"Lord of the Rings"=>4, :Inception=>4, "Hurt Locker"=>3.5, :Mother=>4}
user_input = " lordOF the ring s \n\n\n"
>> movies.transform_keys{|k| normalize_string(k)}
=> {"lordoftherings"=>4, "inception"=>4, "hurtlocker"=>3.5, "mother"=>4}
>> normalize_string(user_input)
=> "lordoftherings"
>> movies.transform_keys{|k| normalize_string(k)}[normalize_string(user_input)]
=> 4
Hash keys and user input are processed by the same function where we try to arrive at one common string.
normalized_movies = movies.transform_keys{|k| normalize_string(k)}
case choice
when "add"
puts "What movie would you like to add? "
title = gets.strip # .chomp
normalized_title = normalize_string(title)
# flip if/else instead of .nil?
if (rating = normalized_movies[normalized_title])
puts "That movie already exists! Its rating is #{rating}."
else
puts "What rating does the movie have? "
movies[title] = gets.chomp.to_i
# ^
# NOTE: use the original title when creating a new key
# with spaces and capitalization.
end
end
https://rubyapi.org/3.1/o/regexp
https://rubyapi.org/3.1/o/hash#method-i-transform_keys
https://rubyapi.org/3.1/o/string#method-i-strip
Upvotes: 2