Chapter 5. Loops and Iterators

image with no caption

Much of programming is concerned with repetition. Maybe you want your program to beep 10 times, read lines from a file as long as there are more lines to read, or display a warning until the user presses a key. Ruby provides a number of ways of performing this kind of repetition.

for Loops

In many programming languages, when you want to run a bit of code a certain number of times, you can just put it inside a for loop. In most languages, you give a for loop a variable initialized with a starting value that is incremented by 1 on each turn through the loop until it meets some specific ending value. When the ending value is met, the for loop stops running.

Here’s a version of this traditional type of for loop written in Pascal:

(* This is Pascal code, not Ruby! *)
for i := 1 to 3 do
   writeln( i );

You may recall from the previous chapter that Ruby’s for loop doesn’t work like this at all! Instead of giving it starting and ending values, you give the for loop a list of items, and it iterates over them, one by one, assigning each value in turn to a loop variable until it gets to the end of the list.

For example, here is a for loop that iterates over the items in an array, displaying each in turn:

for_loop.rb

# This is Ruby code...
for i in [1,2,3] do
   puts( i )
end

The for loop is more like the “for each” iterator provided by some other programming languages. The items over which the loop iterates don’t have to be integers. This works just as well:

for s in ['one','two','three'] do
   puts( s )
end

The author of Ruby describes for as “syntax sugar” for the each method, which is implemented by collection types such as Arrays, Sets, Hashes, and Strings (a String being, in effect, a collection of characters). For the sake of comparison, this is one of the for loops shown earlier rewritten using the each method:

each_loop.rb

[1,2,3].each  do |i|
   puts( i )
end

As you can see, there isn’t really all that much difference. To convert the for loop to an each iterator, all I’ve had to do is delete for and in and append .each to the array. Then I’ve put the iterator variable, i, between a pair of upright bars after do. Compare these other examples to see just how similar for loops are to each iterators.

for_each.rb

# --- Example 1 ---
# i) for
for s in ['one','two','three'] do
   puts( s )
end

# ii) each
['one','two','three'].each do |s|
   puts( s )
end

# --- Example 2 ---
# i) for
for x in [1, "two", [3,4,5] ] do puts( x ) end

# ii) each
[1, "two", [3,4,5] ].each do |x| puts( x ) end

Note, incidentally, that the do keyword is optional in a for loop that spans multiple lines, but it is obligatory when it is written on a single line:

# Here the 'do' keyword can be omitted
for s in ['one','two','three']
   puts( s )
end

# But here it is required
for s in ['one','two','three'] do puts( s ) end

This example shows how both for and each can be used to iterate over the values in a range:

for_each2.rb

# for
for s in 1..3
   puts( s )
end

# each
(1..3).each do |s|
   puts(s)
end

for_to.rb

Note, incidentally, that a range expression such as 1..3 must be enclosed between parentheses when used with the each method, or Ruby assumes you are attempting to use each as a method of the final integer (a Fixnum) rather than of the entire expression (a Range). The parentheses are optional when a range is used in a for loop.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.39.60