Jump start: Lesson 11
- Vocabulary: blocks, loops, iterator, iteration, iteration variable, counter-controlled, sentinel-controlled, loop table, times loop, range, while loop
- To know the purpose for iteration in creating programs
- To write loops in order to prevent code duplication and repetition
- To understand how a loop will execute the statements inside and what the resulting output will be
- Review the notes in this section
- Complete Loops Worksheet
- Complete More Loops Worksheet
- Complete Election Time
Blocks (also referred to as closures, especially in other languages like JavaScript) are not a unique features of Ruby, but they're one that many people talk about (and more people use without realizing it!) What is a block?
A section of code which is grouped together.
Zzzzz....
A block is a piece of code that is not executed immediately. Instead, it is stored in a variable or passed to a method as a parameter to be potentially executed at a later time.
Sound complicated? Let's look at some Ruby.
[1,2,3,4].each do |number|
puts number * 100 # <= this is a block. :)
end
[1,2,3,4].each { |number|
puts number * 100 # <= this is a block too! :D
}
number * 100
is a chunk of code, similar to what would be in a method, but in this case we don't need to go through all the trouble of creating a method just to iterate over some numbers.
Block can be identified by either do ... end
or { }
.
Block arguments are defined using a pair of |
(pipe) characters. They look like a slide, so I like to say that we slide arguments into the block. For example:
[1,2,3].each do |number|
puts number # wheeeee! Right down the slide!
end
number
is the block argument, this means that objects given to the block are going to be assigned to the number
variable within the scope of the block. When the code in the block finishes execution, the block arguments are destroyed.
The each iterator is used on a collection of data, like an Array, Hash or Range. This iterator will iterate over each element of the collection, one by one, and provide access to each element using the iteration variable. The each iterator will continue to execute until it has reached the end of the collection.
The each
iterator is comprised of three pieces:
- The collection to be iterated
- The iteration variable to store each value
- The block of code to be executed in the iteration
In the example below, this iterator will iterate over the veggies
array. For each iteration, the vegetable
variable will be assigned to the value of the next element in the array, starting with the first. The block of code will be executed for each vegetable
variable, which will print out the name of the vegetable.
# A list of veggies
veggies = ["carrot", "yam", "zucchini", "spinach"]
veggies.each do |vegetable|
puts "a vegetable: #{vegetable}"
end
output:
a vegetable: carrot
a vegetable: yam
a vegetable: zucchini
a vegetable: spinach
In the example below, this iterator will iterate over the names
array. For each iteration, the name
variable will be assigned to the value of the next element in the array, starting with the first. The block of code will be executed for each name, which will say hello to each person!
# A list of names
names = ["Rey", "Finn", "Han"]
names.each do |name|
puts "Hello #{name}!"
end
output:
Hello Rey!
Hello Finn!
Hello Han!
Loops are programming constructs that help you repeat a code action an arbitrary number of times without copying and pasting the code. Another term for a loop is iteration. All high-level programming languages provide various forms of loops, which can be used to execute one or more statements repeatedly.
For example, if we wanted to print out "hello" five hundred times, we could write:
puts "hello! "
puts "hello! "
puts "hello! "
puts "hello! "
puts "hello! "
# ... 495 more times
Using a loop, we could re-write this as:
500.times do
puts "hello! "
end
There are 2 categories of loops: counter-controlled and sentinel-controlled loops
Counter-controlled loops are used when the number of loops can be determined prior to loop execution. For example, a copying machine copies a paper a set number of times, and we know exactly how many times the copier will copy the paper.
Sentinel-controlled loops are used when the number of loops cannot be determined prior to loop execution. For example, if you do jumping jacks until you get tired, it is uncertain how many jumping jacks you will do before stopping.
There are four types of loops in Ruby that we will start with: times
, range-each
, while
, and until
.
You use the times
iterator to run a block of code N
times.
You can use a times
loops with or without an iteration variable. This variable is denoted between the vertical bars (pipe character) |
and is used to store data associated with the iteration.
In the example below, N
is equal to three. This example does not use an iteration variable.
3.times do
puts "hello! "
end
output:
hello!
hello!
hello!
In the example below, N
is equal to two. This example does use an iteration variable, i
, which will correspond to value of the iteration.
2.times do |i|
puts i # wheeee remember the slide?
end
output:
0
1
The main use of ranges is to express a sequence. Sequences have a start point, an end point, and a way to produce successive values in the sequence.
Ruby creates these sequences using the ..
and ...
range operators. The two-dot form creates an inclusive range, while the three-dot form creates a range that excludes the specified high value. The each
loop using a range uses an iteration variable (again passed to the block between |
characters), num
in this example.
# Inclusive range example
# note the ..
(5..9).each do |num|
puts num
end
# output
5
6
7
8
9
# Exclusive range example
# note the ...
(5...9).each do |num|
puts num
end
# output
5
6
7
8
The while
loop is useful when you want to continue doing an action while a certain condition is true
but you may not know how many times you'll need to complete that action. It is an example of a sentinel-controlled loop. As soon as the condition stops being true, the loop will terminate.
i = 0
while i < 4
puts i
i += 1
end
The above code will output the values of i until i is no longer less than 4, resulting in the following output:
0
1
2
3
Iteration | i | i < 4 | Output |
---|---|---|---|
1 | 0 | True | 0 |
2 | 1 | True | 1 |
3 | 2 | True | 2 |
4 | 3 | True | 3 |
5 | 4 | False | <None> |
You can read the condition and execute of the while
loop as while condition is true do...
A while loop example: This loop repeats while the user enters "yes".
again = "yes"
while again == "yes"
puts "Let's play a game!"
puts "..."
puts "Would you like to play again? (yes/no) > "
again = gets.chomp
end
The until
loop acts as an inverse of the while
loop. The loop will execute until the condition evaluates as true
.
i = 0
until i == 4
puts i
i += 1
end
The above code will output the values of i until i is equal to 4, resulting in the following (equivalent to the while
loop) output:
0
1
2
3
Iteration | i | i == 4 | Output |
---|---|---|---|
1 | 0 | False | 0 |
2 | 1 | False | 1 |
3 | 2 | False | 2 |
4 | 3 | False | 3 |
5 | 4 | True | <None> |
You can read the condition and execute of the until
loop as until condition is true do...
An until loop example: This loop will repeat until the user guesses the number 6.
number = 0
until number == 6
puts "Guess my number (1-10) > "
number = gets.chomp.to_i
end
puts "You guessed it!"