I am working through exercises on codecademy and I came across a solution that I do not completely understand involving .nil? Here is my code :
movies = { GIS: 10.0, Phantasm: 1.5, Bourne: 4.0}
puts "Whats your movie brah?"
title = gets.chomp
puts "What's your rating brah?"
rating = gets.chomp
movies[title.to_sym] = rating.to_i
puts "Your info was saved brah!"
case movies
when 'add'
puts "What movie do you want to add son?"
title = gets.chomp
if movies[title.to_sym].nil?
puts "What's your new rating brah?"
rating = gets.chomp
movies[title.to_sym] = rating.to_i
puts "#{title} has been added with a rating of #{rating}."
else
puts "That movie already exists! Its rating is #{movies[title.to_sym]}."
end
when "update"
if movies[title.to_sym].nil?
when "display"
puts "Movies!"
when "delete"
puts "Deleted!"
else puts "Error!"
end
I am only referring to the add method. the rest of the script is a work in progress. I don't like not understanding things though and this has me in a bit of a quandry.
My question is does Ruby know not to add a title that already exists because two symbols cannot have the same name? I am curious how it determines when the hash has no value. Can anyone clarify this for me? I would really appreciate it!
The answer is a bit more complicated than that.
From the RubyDoc: "Two objects refer to the same hash key when their hash value is identical and the two objects are eql? to each other."
An object's hash value is a calculated numerical result based on the data the object contains. And the eql? method tests if two objects are equal, and this is usually aliased to == in ruby (i.e my_string1 == my_string2 is the same as my_string1.eql? my_string2).
When you say movies[title.to_sym], Ruby is saying "In the movies hash, are there any pairs currently stored where the key.eql? title.to_sym and key.hash == title.to_sym.hash? If so, return that value of the pairing, and if not return nil.
The reason Ruby doesn't add the title if it already exists is because of your if movies[title.to_sym].nil? line, which in English translates to "only do what follows if no pairing for the key title.to_sym exists."
If you had title = "GIS", and you were to just say movies[title.to_sym] = 1, Ruby would gladly over write the 10.0 you currently have stored there so that movies[:GIS] returned 1.
Related
so the assignment is I'm making a case statement and adding movies paired with their rating in a hash. The "add" case is supposed to add a prompted movie with its paired rating to a hash. It's also supposed to check if the movie already exists in the hash and prompts the user if it does. There's an "update" case which allows the user to update a movie within the hash and also checks if the user inputs a movie that isn't in the hash. Now the update case works fine, it lets the user know if the movies doesn't exist however, I don't think the else part of the add case is working properly? I can add "Wall-E" with a rating of 10 and it doesn't prompt me saying it's already there.
movies = {
"Wall-E" => 10
}
puts "Please choose to add, update, display or delete movies"
choice = gets.chomp
case choice
when "add"
puts "Please name a movie you wish to add"
title = gets.chomp
puts "Please give a rating for this movie"
rating = gets.chomp
if movies[title.to_sym].nil? == true
movies[title.to_sym] = rating.to_i
puts "#{title} was added with a rating of #{rating}"
else
puts "The movie you entered has already been added"
end
when "update"
puts "Please name a movie you wish to update"
title = gets.chomp
if movies[title].nil? == true
puts "Hey bud, that one doesn't exist but you can add it if you want"
else
puts "Please give a rating for this movie"
rating = gets.chomp
movies[title.to_sym] = rating.to_i
end
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 7 years ago.
Improve this question
I am working through a codeacademy project and I cannot get a certain condition to display. Here is my code.
When I select add and choose a movie to add, I want it to let me know if the movie I input already exists in the hash. When I type in a movie that already exists in the hash, it asks me for the rating anyway. I believe I have the else statement in the right place, but it does not seem to be working.
Update: I changed these two lines of code (removing the .to_sym)
title = title
if movies[title].nil?
It does not allow me to enter duplicates.
Now when I choose "add" then try to add "Memento" I get the error message
"#{title} already exists. Its rating is #{rating}!" #{rating} produces an integer of 1 (which makes no sense since the integer value is 4).
movies = {
"Memento" => 4,
"Inception" => 3,
"The Prestige" => 2,
"Interstellar" => 1
}
puts "What would you like to do?"
choice = gets.chomp.downcase
case choice
# ADD
when "add"
puts "What would you like to add?"
title = gets.chomp
title = title
if movies[title].nil?
puts "What its rating? (enter 1-4)"
rating = gets.chomp
movies[title.to_sym] = rating.to_i
puts "#{title} has been added with a rating of #{rating}"
else puts "#{title} already exists. Its rating is #{rating}!"
end
# UPDATE
when "update"
puts "Updated!"
# DISPLAY
when "display"
puts "Movies!"
# DELETE
when "delete"
puts "Deleted!"
# ERROR
else
puts "Error!"
end
When you removed the to_sym calls you didn't remove all of them:
movies[title.to_sym] = rating.to_i
and
Its rating is #{rating}!"
doesn't reference the movie rating it references the variable rating. Which hasn't been set yet.
the else block should be
rating = movies[title]
puts "#{title} already exists. Its rating is #{rating}!"
Since title is a string, you don't need to convert it to a symbol. And then you can use Hash::include? to see if the key exists.
# ADD
when "add"
puts "What would you like to add?"
title = gets.chomp
# title = title.to_sym # delete this line since the hash keys are strings
if !movies.include? title # use Hash::include? to see if key exists
puts "What its rating? (enter 1-4)"
rating = gets.chomp
...
else
puts "Movie already exists. Its rating is #{movies[title]}!" # remove .to_sym
end
I can't find the error, it keeps telling me: Oops, try again. It looks like you didn't add to the movies hash!
Thank you.
movies = { 'himym' => 5,
'oitnb' => 4 }
puts "Which one do you like better?"
choice = gets.chomp
case choice
when "add"
puts "What is your favorite movie?"
title = gets.chomp
puts "What would you rate it?"
rating = gets.chomp
movies = {}
movies[title] = rating
puts "#{title} with rating #{rating} has been added!"
when "update"
puts "Updated!"
when "display"
puts "Movies!"
when "delete"
puts "Deleted!"
else
puts "Error!"
end
I tested your code - I got stuck in the same part. Instructions at CodeAcademy are not always clear. Your code, according to what CA is asking is right, you just need to write "add" as an answer for "Which one do you like better?" when testing code at CA's virtual machine. So:
choice = "add"
That way you will be running your case/when filter. Got it?
I'm trying to complete the "A Night at the Movies" Ruby course on CodeCademy, and encountered a little issue: My code doesn't pass if I use downcase! on choice and the input is lower-case - if it contains an upper-case letter or is entirely upper-case, it works fine.
Here's my code:
movies = {
Foo: "Bar",
}
puts "Commands:"
puts "Add - Add a movie and its rating."
puts "Update - Update a movie's rating."
puts "Display - Display all movies and their ratings."
puts "Delete - Delete a movie and its rating."
choice = gets.chomp.downcase!
case choice
when 'add'
puts "Added!"
when 'update'
puts "Updated!"
when 'display'
puts "Movies!"
when 'delete'
puts "Deleted!"
else
puts "Error!"
end
Help?
Try using #downcase instead of #downcase!.
The reason your code is not passing is because when using #downcase! on an already lowercased string, the result returned is nil, which is what then gets assigned to your choice variable.
Using #downcase would return the string itself, even if the provided string is already lowercased.
Hope it helps!
I have to update and add a movie title and its associated rating to an existing hash. This is the code that i have so far:
movies = {
Titanic:4,
Bestman: 3,
Agora: 2
}
puts "What would you like to do?"
choice = gets.chomp
case movies
when "add"
puts "What movie do you want to add?"
title = gets.chomp
puts "What's the rating of the movie?"
rating = gets.chomp
movies[title] = rating
puts "#{title} has been added with a rating of #{rating}."
when "update"
puts "Updated!"
when "display"
puts "Movies!"
when "delete"
puts "Deleted!"
else
puts "Error!"
end
When I run the code, I get this error "it looks like you didn't add to the movies hash"
I know the error lies somewhere between these lines:
case movies
when "add"
puts "What movie do you want to add?"
title = gets.chomp
puts "What's the rating of the movie?"
rating = gets.chomp
movies[title] = rating
puts "#{title} has been added with a rating of #{rating}."
I have been trying to figure it out but thus far have failed to figure out what I am doing wrong.
Is there an alternative way to add to my movies hash? And what is wrong with my puts code for letting the user know that his/her movie title and rating has been added?
Thank you
EDIT
As pointed out by Some Guy, changing the case statement from
case movies
to
case choice
resolved the issue.
What I need to learn/figure out is why the 2nd works but the 1st does not.
Change
case movies
to
case choice # because this is where your choice of what to do is being stored
If it's still not clear, it may help to think of a case statement as a series of if/elsif (there are differences, but for this scenario it works), so:
case movies
when "add" # do stuff
is akin to:
if movies == "add"
# do stuff
end
Hoping that makes it clearer.