Slides
Iterators
Ref. WGR Section 6.3, "Iterators and code blocks"
Loops as Methods
- An Iterator is a method that allows you to loop through all the members of a collection
 - Works like "for" or "while" but without any extra language keywords
 - It executes a block again and again
 - Usually this block is the default block
- this lets you define the block during the method call
 - concise and readable (arguably)
 
 
times is on your side
potatoes = nil
3.times do |i|
  potatoes = i+1
  puts "#{potatoes} potato"
end
puts potatoes + 1
prints
1 potato
2 potato
3 potato
4
implementing times using until
def times x
  i = 0
  until i == x
    yield i
    i += 1
  end
  x
end
(times returns the number itself)
to each his own
    ["apple", "banana", "cherry"].each do |fruit|
      puts "I love #{fruit}!"
    end
warning: each returns the collection, not the value
def count_chars a
  c = 0
  a.each do |s|
    c += s.length   # this returns c
  end               # but this returns a
  c                 # so this returns c (again)
end
count_chars ["apple", "banana", "cherry"]
=> 17
implementing each using until
def each a
  i = 0
  until i == a.size
    yield a[i]
    i += 1
  end
  a
end
the map is not the territory
["apple", "banana", "cherry"].map do |fruit|
  fruit.reverse
end
=> ["elppa", "ananab", "yrrehc"]
implementing map using each
def map input
  a = []
  input.each do |item|
    a << yield(item)
  end
  a
end
Other Awesome Iterators
- 
select(aliasfind_all)- returns all items for which the block returns true(ish)
 
 - 
reject- returns all items for which the block returns false(ish)
 
 - 
collect(aliasmap)- makes a new array out of whatever the block returns
 
 - 
detect(aliasfind)- returns a single item, not an array
 - returns the first item which makes the block return true(ish)
 
 - 
inject- accumulates (huh?) -- more on this later
 
 
Ref. Using Select Etc.
lethal injection
- 
injectis a really fun iterator, but it's really weird - it passes a persistent "accumulator" to each iteration
 the return value of the block becomes the next accumulator
- 
"inject" is also called "reduce", "fold", and "accumulate" in other languages
 
inject example
  class Array
    def sum
      self.inject(0) do |total, current| 
        total + current
      end
    end
  end
  [1,2,3].sum #=> 6
- To help understand this, write out a table with the values of total, current, and the return value for each iteration.
 
inject reduced
You can also send inject (or reduce) the name of a method only:
class Array
  def sum
    self.reduce(:+)
  end
end
[1,2,3].sum #=> 6
Here we are "reducing" the array by calling + on all its elements in succession.
more help
- Visualizing iterators with colored block diagrams: http://fablednet.posterous.com/thinking-about-iterators
 
Outline
- Iterators
 - Loops as Methods
 - `times` is on your side
 - implementing `times` using `until`
 - to `each` his own
 - warning: each returns the *collection*, not the *value*
 - implementing `each` using `until`
 - the `map` is not the territory
 - implementing `map` using `each`
 - Other Awesome Iterators
 - lethal `inject`ion
 - `inject` example
 - `inject` reduced
 - more help