Skip to content

Ruby Loops

Ruby Loops and Iterators: Repeating Actions

Section titled “Ruby Loops and Iterators: Repeating Actions”

Loops are fundamental control structures that allow you to execute a block of code multiple times. Ruby offers traditional loop keywords and, more idiomatically, a powerful set of iterator methods.

Rubyists often prefer using iterator methods provided by collections (like Arrays and Hashes) and other objects over traditional loop constructs. Iterators are concise, expressive, and often manage scope better.

each Iterator:

The each iterator is one of the most common. It iterates over each element of a collection.

#!/usr/bin/ruby
fruits = ["apple", "banana", "cherry"]
fruits.each do |fruit|
puts "I love #{fruit}s!"
end
# Short block syntax:
(1..3).each { |number| puts "Number: #{number}" }

Output:

I love apples!
I love bananas!
I love cherrys!
Number: 1
Number: 2
Number: 3

times Iterator:

Executes a block a specific number of times.

#!/usr/bin/ruby
3.times do |i|
puts "Iteration number #{i + 1}"
end

Output:

Iteration number 1
Iteration number 2
Iteration number 3

Other Common Iterators: map, select, reject, upto, downto, etc. These provide powerful ways to transform and filter collections. (See the Arrays chapter for more on map, select, etc.)

While iterators are often preferred, Ruby also supports traditional loop keywords.

Executes code as long as a condition is true.

Syntax:

while condition [do]
# code to execute
end

Example:

#!/usr/bin/ruby
count = 0
limit = 3
while count < limit do
puts "Inside the while loop, count = #{count}"
count += 1
end

Output:

Inside the while loop, count = 0
Inside the while loop, count = 1
Inside the while loop, count = 2

Syntax:

# code to execute while condition
# or more commonly for one-liners:
begin
# code
end while condition

Example:

#!/usr/bin/ruby
value = 0
begin
puts "Value is #{value}"
value += 1
end while value < 3

Output:

Value is 0
Value is 1
Value is 2

Executes code as long as a condition is false (i.e., until it becomes true).

Syntax:

until condition [do]
# code to execute
end

Example:

#!/usr/bin/ruby
counter = 5
until counter <= 0 do
puts "Inside the until loop, counter = #{counter}"
counter -= 1
end

Output:

Inside the until loop, counter = 5
Inside the until loop, counter = 4
Inside the until loop, counter = 3
Inside the until loop, counter = 2
Inside the until loop, counter = 1

Syntax:

# code to execute until condition
begin
# code
end until condition

Example:

#!/usr/bin/ruby
stock = 3
begin
puts "Processing item, stock remaining: #{stock}"
stock -= 1
end until stock == 0

Output:

Processing item, stock remaining: 3
Processing item, stock remaining: 2
Processing item, stock remaining: 1

Iterates over elements of a collection (or any object that responds to each).

Syntax:

for loop_variable in expression [do]
# code to execute
end

Example:

#!/usr/bin/ruby
for i in 0..2 # Iterates through the range 0 to 2 (inclusive)
puts "Value of local variable is #{i}"
end
colors = ["red", "green", "blue"]
for color in colors
puts "Color: #{color}"
end

Output:

Value of local variable is 0
Value of local variable is 1
Value of local variable is 2
Color: red
Color: green
Color: blue

Note: A for...in loop is roughly equivalent to (expression).each do |loop_variable| ... end. However, a key difference is that for...in does not create a new scope for the loop_variable, whereas each with a block does. For this reason and for consistency, each is generally preferred in modern Ruby.

Ruby provides statements to control the flow within loops:

break Statement:

Terminates the innermost loop immediately.

#!/usr/bin/ruby
(0..4).each do |i|
if i == 3 then
puts "Breaking at i = #{i}"
break
end
puts "Value of i is #{i}"
end

Output:

Value of i is 0
Value of i is 1
Value of i is 2
Breaking at i = 3

next Statement:

Skips the rest of the current iteration and proceeds to the next iteration of the innermost loop.

#!/usr/bin/ruby
(0..4).each do |i|
if i == 2 then
puts "Skipping i = #{i}"
next
end
puts "Value of i is #{i}"
end

Output:

Value of i is 0
Value of i is 1
Skipping i = 2
Value of i is 3
Value of i is 4

redo Statement:

Restarts the current iteration of the innermost loop from the beginning, without re-evaluating the loop’s condition (if any).

#!/usr/bin/ruby
attempts = 0
(0..2).each do |i|
puts "Attempting task for i = #{i}, attempt ##{attempts + 1}"
if i == 1 && attempts < 2 then
attempts += 1
puts "Redoing for i = #{i}"
redo # Restarts this iteration (for i = 1)
end
puts "Completed task for i = #{i}"
attempts = 0 # Reset for next i
end

Output:

Attempting task for i = 0, attempt #1
Completed task for i = 0
Attempting task for i = 1, attempt #1
Redoing for i = 1
Attempting task for i = 1, attempt #2
Redoing for i = 1
Attempting task for i = 1, attempt #3
Completed task for i = 1
Attempting task for i = 2, attempt #1
Completed task for i = 2

Note: redo can easily lead to infinite loops if not used carefully. It’s less common than break or next.

retry Statement:

The retry statement is primarily used within rescue blocks to re-execute the entire begin...end block where an exception occurred. Its use directly within loops (outside a rescue clause) is rare and can be confusing, as it typically restarts the entire loop or iterator from its very beginning.

Example of retry in a rescue clause (its common use):

#!/usr/bin/ruby
retries_left = 2
begin
puts "Attempting operation..."
# Simulate an error sometimes
raise "Simulated network error" if rand(3) == 0 && retries_left > 0
puts "Operation successful!"
rescue => e
puts "Error: #{e.message}"
if retries_left > 0
retries_left -= 1
puts "Retrying... (#{retries_left} retries left)"
retry # Restart the begin block
else
puts "No more retries. Operation failed."
end
end

Practical Applications:

Loops and iterators are used everywhere: processing user input, reading files line by line, iterating over database records, rendering UI components, performing calculations repeatedly, and much more. Choosing the right looping construct (often an iterator like each or map) can make your Ruby code more readable and efficient.