for
and each
loops. In practical terms, there is not a lot between for and each besides style, though each
is actually a method call that takes a block, while for seems to be a language feature. They both iterate over a collection, which could be a hash, a string, an array or a range. Let us look at ranges first.For and each with ranges
Use of a range takes the place of the normal for/next loop. In these examples, 1..10 and 1...11 are
Range
objects; the three dots indicates that the end stops before the terminator, two dots indicates it includes the terminator. These three examples will all print out the numbers 1 to 10, illustrating the difference between each and for, and the two and three dots.for i in 1..10
do_stuff
end
for i in 1...11
do_stuff
end
(1..11).each do i
do_stuff
end
Ruby is perfectly happy with characters and variables in a
Range
object, and the next example shows how a range can be assigned to a variable.r = 'a'..'z'
for i in r
puts i
end
n = 5
(1..n).each do i
puts i
end
These loops output the
Range
object, by the way, and you can test if something is within a range using the member?
method (eg r.member? "c"
).A quick note about arrays and ranges. I got really confused by putting square brackets around a range. What is [1..5]? This is an array with a single member, and that member is a Range object.
For and each with arrays, hashes and strings
The
each
method allows you to iterate over each member of a string, an array or a hash.array.each { member do_stuff_with(member) }
array.each do member
do_stuff_with(member)
end
For a hash, you pass two values to the block
hash.each { key, value do_stuff_with(key, value) }
hash.each do key, value
do_stuff_with(key, value)
end
You can use the
for
feature with hashes and arrays too, for example:h = {:a => 19, :b => 35, :c => 3456}
for k, v in h
puts "key=#{k} value=#{v}"
end
The times method
In Ruby everything is an object, and integer objects (of the class
Fixnum
) have a method called times
, which, like each, accepts a block, and iterates from zero up to one less that the number. In these examples, the numbers zero to nine are printed.10.times { i puts(i) }
10.times do i
puts i
end
n = 10
n.times { i puts i }
Invoking times on a negative number will create a loop with zero iterations!
The yield feature
You can easily define your own methods that work like
each
and times
, using the keyword yield
. Say this method is defined in a class, Car:def cars
yield "Red car"
yield "Green car"
yield "Blue car"
end
The following will then produce a list of cars; red, green and blue.
m = MyClass.new
m.cars { c puts c }
The cars method runs until it hits the
yield
, and at that point passes the value back to the calling code, which then processes it as required. Then the loop goes again, and the cars method continues to the next yield stament. The loop iterates until it runs out of yield
s (the cars method will run to the end regardless of any further yield
s in the code).The while and until loops
Ruby also supports
while
and until
. The until
loop is just a while not
loop. There appears to be no option to check the conditional after the iteration that I have found.Infinite loops
You can also create infinite loops with the
loop
method. Hmm, beter make sure there is some way to break out of the loop, which brings us to:The break, redo, retry, next and return keywords
Ruby also has some interesting keywords to modify loop behaviour. As with C and derivatives, the
break
statement drops you out of the current loop. The next
statement replaces continue; it stops the current iteration, moves to the next one, and passes control to the condition at the end of the loop. The retry
statement is similar, but does not move to the next iteration; it repeats the current one. The redo
statement starts the whole loop from the first iteration. There is also a return
statement, which drops you straight out of the entire method (and optionally takes a parameter; a value returned by the method).Struggling with Ruby: Contents Page
No comments:
Post a Comment