Topics Covered: creating, updating, iterating over arrays (lists); same for hashes (dictionaries); symbols; basic methods; options hash for methods
Write a program that prints out the array ["apples", "bananas", "carrots", 4]
in reverse. Don't just .reverse
the array in the code.
$ ruby reverse.rb
4
carrots
bananas
apples
Hover for answer
# reverse.rb
list = ["apples", "bananas", "carrots", 4]
index = list.length - 1
while index >= 0
puts list[index]
index -= 1
end
# alternate solution
list = ["apples", "bananas", "carrots", 4]
list.each_with_index do |item, index|
puts list[list.length - index - 1]
end
# alternate (cheeky) solution
list = ["apples", "bananas", "carrots", 4]
list.reverse.each do |item|
puts item
end
# If it's a short loop, you can do it on one line:
list.each_with_index { |item, index| puts list[list.length-index-1] }
Write a program (also called a script) that prints the numbers from 1-100, but for each multiple of 3, print "fizz", each multiple of 5 print "buzz" and each multiple of 3 and 5 print "fizzbuzz":
$ ruby fizzbuzz.rb
1
2
fizz
4
buzz
...
13
14
fizzbuzz
16
...
The modulo operator returns the remainder when the first input is divided by the second. That is, 10 modulo 4 would return 2. A quick way to check if a number is divisible by another is to see if their modulo is 0. In ruby, the %
symbol is the modulo operator, that is 10 % 4 == 2
.
Hover to show answer
# fizzbuzz.rb
# One possible solution:
100.times do |x|
x = x+1 # because x starts at 0 and ends at 99
mult_3 = (x % 3 == 0)
mult_5 = (x % 5 == 0)
if mult_3 && mult_5
puts "fizzbuzz"
elsif mult_3
puts "fizz"
elsif mult_5
puts "buzz"
else
puts x
end
end
# Alternate solution after optimizations/tweaks:
# https://gist.github.com/sansari/fe88c1dd395cbd9d0f64
While we've primarily seen examples of hashes mapping strings to integers or vice versa, the values can actually be anything (like array, or even other hashes). Create a hash (in ingredients.rb
) that maps a dish name (i.e. "Hash browns") to a list of necessary ingredients (i.e. "Potatoes", "Butter", "...is there anything else?"). Add at least 3 dishes. Each dish should have at least 3 ingredients.
Create a new file recipes.rb
. This time, map each dish name to another hash. That hash should have keys :description
(which maps to a String
), :ingredients
(which maps to an array of Strings, like above, and :steps
(which maps to an array of Strings that, you guessed it, tell you how to make the dish).
For example, you might have something that looks like:
cookbook = {
"Hash browns" => ...
"Pancakes" => ...
}
The goal is to be able to type something like cookbook["Pancakes"]
and get a description, an ingredients list, and steps for how to make the dish.
If you finish early, cook one of those dishes for your TA.
Hover to show answer
# recipes.rb
cookbook = {
"Hash browns" => {
:description => "fun and brown",
:ingredients => ["potatoes", "butter", "...is there anything else?"],
:steps => ["1. hash", "2. cook", "3. eat"]
},
"Pancakes" => {
:description => "fun and flat",
:ingredients => ["flour", "water", "...is there anything else?"],
:steps => ["1. mix", "2. heat on pan", "3. eat"]
}
# ... etc.
}
# Or in the new syntax (symbols can't have spaces, so we use underscores)
cookbook = {
hash_browns: {
description: "fun and brown",
ingredients: ["potatoes", "butter", "...is there anything else?"],
steps: ["1. hash", "2. cook", "3. eat"]
},
pancakes: {
description: "fun and flat",
ingredients: ["flour", "water", "...is there anything else?"],
steps: ["1. mix", "2. heat on pan", "3. eat"]
}
# ... etc.
}
hash = {
:a => {
:b => ["c", "d"]
},
:e => "f"
}
When describing complex objects, it's nice to have a way to describe them. If I were to describe a hash that maps a symbol to a string, for example, I would write Hash<Symbol, String>
. For nested structures: Hash<Symbol, Array<String>>
(a hash that maps a symbol to an array of strings). Write down the signatures for:
ingredients.rb
In d2
, create a program that asks the user for items. Add each item to a list, and print out the whole list after each item.
$ ruby list_builder.rb
Welcome to list builder!
What can I add?
yummy things
Added! Your list is:
["yummy things"]
What can I add?
icky things
Added! Your list is:
["yummy things", "icky things"]
To keep a program running forever, put your code in a while true
loop. To exit such a program, press Ctrl-c
in the shell.
Hover for answer
# list_builder.rb
puts "Welcome to list builder!"
list = []
while true do
puts "What can I add?"
item = gets.strip
list.push(item)
puts "Added! Your list is:"
p list # p is like puts, but works with all objects, not just strings
end
Create an extensive list builder, that allows you to add items with a command like add x
, remove items with remove x
, and quit with quit
$ ruby ext_list_builder.rb
Welcome to list builder++!
What can I do for you?
add a
Added! Your list is:
["a"]
What can I do for you?
add b
Added! Your list is:
["a", "b"]
remove a
Removed! Your list is:
["b"]
quit
Bye!
This is the pinnacle—it'll require knowledge from all the exercises up until this point! Since the program will be long, you may want to sketch out a solution before you start coding—remember what we said about planning. How do you keep track of whether you're done? What if the user makes a typo, tries a different command, or tries to remove something not in the list? Can they they see the list of available commands somehow? After you come up with a solution, try to stress test, and check for edge cases (not typing anything, typing many words, etc.). Then ask one of the TA's to stress test for you and find any bugs!
Hover for answer
# ext_list_builder.rb
puts "Welcome to list builder++!"
list = []
while true do
puts "What can I do for you?"
command = gets.strip
tokens = command.split(" ")
if tokens[0] == "add"
item = tokens[1]
list.push(item)
puts "Added! Your list is:"
p list
elsif tokens[0] == "remove"
item = tokens[1]
list.delete(item)
puts "Removed! Your list is:"
p list
elsif tokens[0] == "quit"
puts "Bye!"
break
elsif tokens[0] == "help"
puts "You can add items with 'add x', remove items with 'remove x' and quit with 'quit'."
else
puts "Command not recognized"
end
end
Extend your program to use a Hash
instead of an Array
, and keep track of how many of each item the user has added.
$ ruby container.rb
Welcome to container builder!
What can I do for you?
add a
Added! Your container has:
{"a"=>1}
What can I do for you?
add b
Added! Your container has:
{"a"=>1, "b"=>1}
What can I do for you?
add a
Added! Your container has:
{"a"=>2, "b"=>1}
remove a
Removed! Your container has:
{"a"=>1, "b"=>1}
quit
Bye!
Hover for answer
# ext_list_builder.rb
puts "Welcome to container builder!"
container = {}
while true do
puts "What can I do for you?"
command = gets.strip
tokens = command.split(" ")
if tokens[0] == "add"
item = tokens[1]
num = container[item]
num = 0 if num == nil
num += 1
container[item] = num
puts "Added! Your container has:"
p container
elsif tokens[0] == "remove"
item = tokens[1]
num = container[item]
if num && num > 0
num = num - 1
container[item] = num
puts "Removed! Your container has:"
p container
else
puts "No such item..."
end
elsif tokens[0] == "quit"
puts "Bye!"
break
elsif tokens[0] == "help"
puts "You can add items with 'add x', remove items with 'remove x' and quit with 'quit'."
else
puts "Command not recognized"
end
end
Translate the following code to use map
.
# map.rb
result = []
engines = ["Google", "Bing", "Ask Jeeves"]
engines.each do |e|
if e == "Google"
result.push("OK")
elsif e == "Bing"
result.push("Bad!")
else
result.push("What is that?")
end
end
result
# => ["OK", "Bad!", "What is that?"]
Hover for answer
# google_map.rb
engines = ["Google", "Bing", "Ask Jeeves"]
result = engines.map do |e|
if e == "Google"
return "OK"
elsif e == "Bing"
return "Bad!"
else
return "What is that?"
end
end
The Fibonacci sequence is one that starts with 1 and 1, and is made by summing the last two elements of the sequence. Thus, the third element is 1+1=2
, the fourth is 1+2=3
, the fifth is 2+3=5
, and so on. Write a program called fibonnaci.rb
that takes an integer from the user and computes that Fibonnaci number. If you've seen recursive Fibonacci before, note, we would like you to write it the iterative way.
$ ruby fibonacci.rb
Enter a number:
1
Fibonnaci at 1: 1
$ ruby fibonacci.rb
Enter a number:
4
Fibonnaci at 4: 3
$ ruby fibonacci.rb
Enter a number:
10
Fibonnaci at 10: 55
Make sure to test your answers against an online Fibonnaci calculator (Wolfram Alpha should do). How long does your code take to compute 10,000? 100,000? 1,000,000? Can you make it faster?
Hover for answer
# fibonnaci.rb
puts "Enter a number:"
num = gets.to_i # no need for both strip and to_i
fib = 1
two_before = 1
one_before = 1
if num > 2
(num-2).times do
two_before = one_before
one_before = fib
fib = two_before + one_before
end
end
puts "Fibonnaci at #{num}: #{fib}"`
rubeque.com is a great site for simple Ruby puzzles. Try some out. To get you started:
split
and map
!)The final push! You'll be briefly presenting your website to the class tomorrow, so give it your all. This is what The Bru came up with, in less than 100 lines of HTML and 100 lines of CSS.