JumpStart: Lesson 11
- Vocabulary: loops, iterator, iteration, iteration variable, counter-controlled, sentinel-controlled, loop table, times loop, range, while loop, blocks, scope
- 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 the Numbers problem assignment
- Complete Election Time assignment
- [Optional] For additional learning and practice, look at the lessons and exercises of Day 3 of JumpStart Live and Day 4 of JumpStart Live
Loops are programming constructs that help you repeat a code action a certain number of times based on the algorithmic logic, without needing to copy and paste 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
The above program leverages the times
loop, which is a counter-controlled loop as we will soon see. The same loop may be written using different programming constructs and syntax. For example, we could achieve the same result using a while
loop, which is a sentinel-controlled loop, as we will soon see. Here's a program using a while
loop to achieve the same result:
i = 0
while i < 500
puts "hello! "
i += 1
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. The example we saw above, where we wanted to print hello!
500 times, is an example of counter-controlled loop. Another example of counter-controlled loop could be a copying machine which 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. Another example could be a program which asks the user if the user would like to continue playing a guessing game. Based on comparing the user input value, the program determines whether to continue the loop or exit the loop.
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
end
output:
0
1
Note: As you can see in the example above, in programming, we start counting with 0. The first time the loop executes, the value of the iteration variable will be 0.
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, num
in this example.
# Inclusive range example
# note the ..
(5..9).each do |num|
puts num
end
The above code will output the following:
5
6
7
8
9
# Exclusive range example
# note the ...
(5...9).each do |num|
puts num
end
The above code will output the following:
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 # initialize loop control variable to the value of 0
while i < 4 # loop is executed while value of loop control variable is less than 4
puts i
i += 1 # increment the value of loop control variable by 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
Here's the loop table for the above program:
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 execution of the while
loop as while condition is true do...
Another example of while
loop:
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 # initialize loop control variable to the value of 0
until i == 4 # loop is executed until the value of loop control variable becomes 4
puts i
i += 1 # increment the value of loop control variable by 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
Here's the loop table for the above program:
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 execution of the until
loop as until condition is true do...
Another example of until
loop:
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!"
The each
iterator is used on a collection of data, like a Range, Array or Hash. We have already come across Range and we will learn more about Arrays and Hashes in later lessons. 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
Note: With the times
loop, the value of the iteration variable begins at 0
and increments by one in each subsequent iteration to the next value: 0
, 1
, 2
and so on. In the each
iterator, the value of the iteration variable begins with the value of first element in the range or array or collection and then moves on to the value of the next element in the range or array or collection as we will see in examples below.
We have already seen some examples of each
iterator on ranges.
We will discuss how each
iterator works with arrays and hashes in the lessons to come.
In programming, a block is a section of code which is grouped together and intended to be executed if a certain condition is satisfied.
A variable defined inside a block is only available within the block and not outside. In other words, the definition of the variable is scoped to the block.
Example:
i = 0
while i < 4 do
# the code between while and end is a block of code
multiple = i * 10
# multiple is scoped to this block
puts "#{i} times 10 is #{multiple}"
i += 1
end
# multiple is an undefined variable
In Ruby, one way to identify some of the blocks is to identify code statements surrounded by either do ... end
or { }
. Aside: At Ada Developers Academy, we prefer using do ... end
over { }
in our code.
[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
}
Block arguments are defined using a pair of |
(pipe) characters. For example:
[1,2,3].each do |number|
puts number
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 out of scope.
- Throughout this course we will be working with the Numbers program. Here's the third version of the program:
- Leveraging your learnings from the notes you read (use at least one loop), write a program that does the following:
- Ask the user for the count of numbers.
- Do the following count number of times:
- Ask the user to input a positive integer value
- If the number is divisible by 3, display a message to share so and a different message otherwise.
- Once you have a working program, refactor your code to use a different type of loop. e.g. if you used a
while
loop to begin with, change it to antimes
loop with iteration variable. - Example output:
- Note: User input is indicated in ~~ (tildes).
- Leveraging your learnings from the notes you read (use at least one loop), write a program that does the following:
Let's play a numbers game. How many numbers would you like to enter?
~5~
Enter the 1st positive integer: ~34~
34 is not divisible by 3.
Enter the 2nd positive integer: ~21~
21 is divisible by 3.
Enter the 3rd positive integer: ~12~
12 is divisible by 3.
Enter the 4th positive integer: ~582~
582 is divisible by 3.
Enter the 5th positive integer: ~80~
80 is not divisible by 3.