Ruby Iterators


Iterators are nothing but methods supported by collections. Objects that store a group of data members are called collections. In Ruby, arrays and hashes can be termed collections.

Iterators return all the elements of a collection, one after the other. We will be discussing a few of Ruby iterators here. Let's look at these in detail.


Ruby each Iterator:

The simplest iterator method. All iterables (such as arrays and hashes) in Ruby will have an each method that will allow you to loop over the values in the iterable and do something with each one.

      [1,2,3,4,5,6,7,8,9,10].each {|value| print "#{value} "}
      

This will produce following result:

      1 2 3 4 5 6 7 8 9 10
      

The each iterator executes code for each element in collection.

      ary = [1,2,3,4,5]
      ary.each do |i|
         puts i
      end
      

This will produce following result:

      1
      2
      3
      4
      5
      

You always use the each iterator with a block. It returns each value of the array, one by one, to the block. The value is stored in the variable i and then displayed on the screen.


Ruby each_index Iterator:

If you have an array and doesn't want to loop over every value but rather over every index, the each_index iterator does the job:

      array = ['A','B','C','D','E','F','G','H','I','J']
      array.each_index {|i| print "#{i}-"}
      

This will produce following result:

      0-1-2-3-4-5-6-7-8-9-
      

Ruby collect Iterator:

The collect iterator returns all the elements of a collection.

The collect method need not always be associated with a block. The collect method returns the entire collection, regardless of whether it is an array or a hash.

      a = [1,2,3,4,5]
      b = Array.new
      b = a.collect
      c = {'a' => 1, 'b' => 2}
      d = c.collect
      puts b.inspect
      puts d.inspect
      

This will produce following result:

      [1, 2, 3, 4, 5]
      [["a", 1], ["b", 2]]
      

NOTE: The collect method is not the right way to do copying between arrays. There is another method called a clone which should be used to copy one array into another array.

You normally use the collect method when you want to do something with each of the values to get the new array. For example, this code produces an array b containing 10 times each value in a.

      a = [1,2,3,4,5]
      b = a.collect{|x| 10*x}
      puts b.inspect
      

This will produce following result:

      [10, 20, 30, 40, 50]
      

Notice: collect has a commonly used alias: "map".

As many other iterators, it can be used to transform one collection into another.

      puts ['Antony', 'Richard','Kathy','Kopf'].map{|x| x.length}.inspect
      

This will produce following result:

      [6, 7, 5, 4]
      

Ruby loop Iterator:

The simplest version of it is the infinite loop:

      loop {puts "HELLO"}
      

This will produce following result:

      HELLO
      HELLO
      HELLO
      HELLO
      .
      .
      .
      

When using the loop iterator, we will need termination and control keywords, Ruby provides: break, next and redo.

      i=0
      loop do
        i+=1
        print "#{i} "
        break if i==10
      end
      

This will produce following result:

      1 2 3 4 5 6 7 8 9 10
      

      i=0
      loop do
        i+=1
        next if i==3
        print "#{i} "
        break if i==10
      end
      

This will produce following result:

      1 2 4 5 6 7 8 9 10
      

You can also pass a parameter to both next and break, and it will become the value returned by the loop.

      for i in 1..5
         puts "How many do you need on day #{i} ?"
         STDOUT.flush
      
         nneed = gets.chomp.to_i
      
      # next - don't order nothing; move on to next case
         next(print 'nothing? ') if nneed == 0
      
      # retry - whole thing to be redone on a 999 code
         retry if [112,911,999].include?(nneed)
      
      # redo - more than 10 ordered - must be a mistake
          if nneed > 10 then 
      	   puts "Too many!"
      	   redo
      	end
      
      # break - code "-1" entered to exit on a short week
         break(print 'stopped! ') if nneed == -1
      
         puts "We'll get #{nneed} on order for day #{i}"
      end
      

This may produce the following result:

      How many do you need on day 1 ?
      0
      nothing? How many do you need on day 2 ?
      911
      How many do you need on day 1 ?
      12
      Too many!
      How many do you need on day 1 ?
      3
      We'll get 3 on order for day 1
      How many do you need on day 2 ?
      4
      We'll get 4 on order for day 2
      How many do you need on day 3 ?
      5
      We'll get 5 on order for day 3
      How many do you need on day 4 ?
      -1
      stopped!
      

Ruby times Iterator:

It is similar the classic for loop in other languages and will allow you to execute a loop and perform an action (according to the block you write) x number of times e.g.:

      10.times {|i| print "#{i} "}
      

This will produce following result:

      1 2 3 4 5 6 7 8 9
      

Ruby upto and step Iterators:

Once again it is similar to the classic for loop in that we execute from number x up to number y (y needs to be bigger than x obviously):

      1.upto(10) {|i| print "#{i} "}
      

This will produce following result:

      1 2 3 4 5 6 7 8 9 10
      

We can also use step to iterate while skipping over a range of numbers on every iteration:

      1.step(10, 2) {|i| print "#{i} "}
      

This will produce following result:

      1 3 5 7 9
      


Ruby has plenty more iterators where "each" came from. Which one should be used depends on what operation you are trying to perform...