The Iterator

Juan Carlos Hinojo

Purpose

 

Its a container interface capable of accessing in a secuential way a group of elements without exposing its primary source or representation.

Types of Iterators

External Iterator

Internal Iterator

Internal Iterator

.each

Internal Iterator

Iterator built-in the collection.

 

Iteration logic occurs inside the aggregate object.

 

You can pass code as a block which will be called for each element in the iteration.

[ 1, 3, 5 ].each { |i| puts i }
def fibUpTo(max)
  i1, i2 = 1, 1
  while i1 <= max
    yield i1
    i1, i2 = i2, i1+i2
  end
end

fibUpTo(1000) { |f| print f, " " }
def threeTimes
  yield
  yield
  yield
end
threeTimes { puts "Hello" }

External Iterator

@array = Array.new(array)

External Iterator

Iteration is dictated by an external class.

 

Iteration logic is separated into a different class.

  • Handle multiple object types.
  • More control over iteration
class ArrayIterator
  def initialize(array)
    @array = Array.new(array)
    @index = 0
  end

  def has_next?
    @index < @array.length
  end

  def next_item
    value = @array[@index]
    @index += 1
    value
  end
end
require './ArrayIterator'

i = ArrayIterator.new(['red', 'green', 'blue'])
while i.has_next?
  puts "item: #{i.next_item}"
end

i = ArrayIterator.new('abc')
while i.has_next?
  puts("item: #{i.next_item}")
end

Enumerable

include Enumerable

Enumerable

 

 

Module with built-in iterators

 

Must define a #each method

which yields each item in the

collection.

class Colors
  include Enumerable

  def each
    yield "red"
    yield "green"
    yield "blue"
  end
end
>> c = Colors.new
>> c.map { |i| i.reverse }
=> ["der", "neerg", "eulb"]
>> [1,2,3,4,5].select { |i| i > 3 }
=> [4,5]
class Portfolio
  include Enumerable

  def initialize
    @accounts = []
  end

  def each(&block)
    @accounts.each(&block)
  end
  
  def add_account(account)
    @accounts << account
  end
end
class Account
  attr_accessor :name, :balance

  def initialize(name, balance)
    @name = name
    @balance = balance
  end

  def <=>(other_account)
    balance <=> other_account.balance
  end
end
require './Account'
require './Portfolio'

portfolio = Portfolio.new
portfolio.add_account Account.new('red', 2000)
portfolio.add_account Account.new('blue', 1000)
portfolio.add_account Account.new('green', 500)

puts portfolio.any? { |account| account.balance > 2000 }
puts portfolio.all? { |account| account.balance >= 10 }

Lazy Iterator

(1..Float::INFINITY).lazy.select { |x| x % 2 == 0 }.first(100)

Resources

http://ruby-doc.com/docs/ProgrammingRuby/html/tut_containers.html

http://chickenriceplatter.github.io/blog/2013/04/07/internal-vs-external-iterators/

http://blog.carbonfive.com/2012/10/02/enumerator-rubys-versatile-iterator/

http://www.sitepoint.com/guide-ruby-collections-iii-enumerable-enumerator/

We are hiring =)

The Iterator

By Juan Carlos Hinojo