Times. We use the times iterator. Iterators can have an iteration variable, but they do not always need one. We can omit the iteration variable for simpler syntax.
Part 1 We use an iterator with no variable. The number 4 is an object, and we invoke times() to repeat 4 times.
Part 2 We add an iteration variable in vertical bars. The variable "i" starts at 0 and is incremented by 1 on each pass through the loop.
# Part 1: use a times-loop.
4.times do
puts "TIMES: 4"
end
# Part 2: use a times iterator with an iteration variable.
5.times do |i|
puts "ITERATION: %d" % i
endTIMES: 4
TIMES: 4
TIMES: 4
TIMES: 4
ITERATION: 0
ITERATION: 1
ITERATION: 2
ITERATION: 3
ITERATION: 4
Upto. This starts at the first number and proceeds through the argument. Here we use iteration variables "x" and "y." We also nest an iterator loop.
And The nested loop uses upto with a variable start and end. An expression, "x + 2," is provided.
Detail The program loops over the indexes 3, 4 and 5. And at each index, it loops over the next two highest numbers.
# Go up from 3 to 5.
3.upto(5) do |x|
# Go up from x to x + 2.
x.upto(x + 2) do |y|
# Display variable.
print y, " "
end
# End the line.
print "\n"
end3 4 5
4 5 6
5 6 7
Upto, short syntax. Iterators can be used with a short block syntax form. We use curly brackets and omit the do keyword. This is shorter to type, but harder to add statements to later.
# Use block syntax.# ... The do keyword is not required here.# ... Use format string with puts to write the numbers.
0.upto(3) {|x| puts("Number: %x" % x)}Number: 0
Number: 1
Number: 2
Number: 3
Downto. This decrements a number. It reduces the number by 1 after each pass through the iterator body. If the argument is not lower, the iterator body is not executed.
Tip The downto iterator is best used for simple loops. The step iterator allows complex or unusual iteration steps—even decrements.
However As a general rule, using the simplest syntax form necessary for any operation is ideal. If downto is effective, use it.
# Decrement from 5 to 3.
5.downto(3) do |j|
# Display the index.
puts j
end5
4
3
Step. This allows us to specify all parts of a loop. We indicate the starting index, the ending index, and the step—the change after each iteration.
Argument 1 This is the ending index. In the first loop, we end at the index 10. In the second, we end at 6.
Argument 2 This is the step. The iteration variable is changed by this amount—positive or negative—after each pass.
# Increment from 0 to 10, by 2 each time.# ... Name the iteration variable "v".
0.step(10, 2) do |v|
puts v
end
# Decrement from 12 to 6, by -2 each time.# ... Name the iteration variable "iter".
12.step(6, -2) do |iter|
puts iter
end0
2
4
6
8
10
12
10
8
6
Step versus upto. Should we always use step? The step method can duplicate the other loops shown. It is powerful, but may be more complex than upto or downto.
Thus A primary reason why we should not always use step is that it introduces further complexity. Using downto, upto or times is simpler.
Tip Code that is simpler to read is less likely to cause bugs. It can be checked and understood faster.
Detail The 2 iterator invocations here do the same thing. But upto requires less syntax, and may be easier to understand.
Each. This is available on arrays. It accesses each array element. With the iteration variable, we can then test and use the element. The index number remains unavailable.
values = [10, 20, 30]
# Use each on the array of integers.# ... Print each value with puts in a single-line block.
values.each {|number| puts "VALUE: %d" % number}VALUE: 10
VALUE: 20
VALUE: 30
Yield. Here we can implement our own iterators. This code introduces an addthree() method, which yields a sequence of numbers starting at zero, incrementing by 3 each time.
Tip With this style of code, we do not need to manage indexes or increment a variable to loop over a custom sequence or range.
Tip 2 With a custom iterator, we can separate the complexity of a loop into a single, reusable method.
def addthree(max)
# Return a sequence incremented by three up to the max.
i = 0
while i <= max
yield i
i += 3
end
end
# Display sequence up to 20.
addthree(20) do |n|
puts n
end0
3
6
9
12
15
18
Benchmark, iterators. Are iterators slower than for-loops? If a certain form of iteration is faster, it can help many programs. Most programs spend most of their time in looping constructs.
Version 1 This version of the code tests the times iterator: it repeats a specific statement 750000 times.
Version 2 Here we use the for-loop with a start index and a max index. It iterates the same number of times as version 1.
Result I found that the iterator was slightly faster. The results were repeatable. The ordering of the tests did not change my results.
So When composing Ruby programs, do not avoid using iterators. They may have better performance than loops.
count = 750000
n1 = Time.now.usec
# Version 1: use times iterator.
v = 0
count.times do
v += 1
end
puts v
n2 = Time.now.usec
# Version 2: use for-loop.
v = 0
for i in 0..count-1
v += 1
end
puts v
n3 = Time.now.usec
# Compute millisecond timings.
puts ((n2 - n1) / 1000)
puts ((n3 - n2) / 1000)750000
750000
61 [Time in ms: times() iterator]
64 [Time in ms: for-loop]
A summary. Ruby iterators help make loops simpler. With them, we eliminate index variables when possible. This reduces code complexity, which in turn prevents bugs.
Dot Net Perls is a collection of tested code examples. Pages are continually updated to stay current, with code correctness a top priority.
Sam Allen is passionate about computer languages. In the past, his work has been recommended by Apple and Microsoft and he has studied computers at a selective university in the United States.