Getting Started with Ruby: Iterators
by Erik Andrejko
April 30, 2009
|
In this article Erik Andrejko will discuss Ruby iterators, a
coding pattern that allows expressive and succinct
programming with collections.
|
Collections are the bread and butter of many programming
languages, including Ruby. The most common collections in
Ruby are Array and Hash. In Ruby
an iterator is a special kind of method defined for
collection objects. Almost always, iterators run a block of
code for each element of a collection to produce either a
new collection or a computation that depends on every
element of the collection. This pattern is so common that
Ruby has a mechanism to simplify creating iterators called
blocks.
Blocks
Blocks are a basic pattern in Ruby, and a part of every
iterator. Iterators typically run the same block of code
for each element in a collection. To simplify the
development of iterators, Ruby supports a mechanism to pass
a block of code as an argument to a method. There are two
different syntaxes for passing blocks. One syntax is to use
a do … end pair:
object.method do |a|
... # block
end
Equivalently the block can be passed on a single line by
using curly braces:
object.method { |a| ... # block }
In both cases, the block passed to method
accepts a single argument specified by |a|.
You will see blocks used frequently in Ruby. In most
cases loops are implemented in Ruby by using a block. For
example:
3.times do
puts "hi"
end
The simplest type of iterator executes a given block of
code for each element of a collection. In Ruby this can be
accomplished by passing a block to the each
method, for example:
[0,-1,3,4].each {|x| puts x}
Transformations
Many iterators are used to transform one collection into
another collection. The most common such iterator is the
map iterator. The map method
applies the provided block to each element of a collection
to produce a new collection.
For example, map can be used to change the
array ['hello', 'world'] into an array of the
length of each string:
['hello', 'world'].map {|x| x.length } # => [5, 5]
Another common transformation is to replace a collection
with a sub collection satisfying a given property. To find
all of the positive elements of [1,-1,2,-3,4,7]
we can use the select method:
[1,-1,2,-3,4,7].select {|x| x > 0} # => [1, 2, 4, 7]
Some applications of select are common
enough that there is a defined shortcut. For instance, to
remove all instances of nil from the array
[nil, "", "a", "aa", "aba", nil] we can use the
compact method:
[nil, "", "a", "aa", "aba", nil].compact # => ["", "a", "aa", "aba"]
It is possible to implement complex methods by chaining
transformations, often in a single line of code. For
example, to find the least positive element of [-1,2,-
3,4,7,1] we could use:
[-1,2,-3,4,7,1].select {|x| x > 0}.sort.first # => 1
Note that each iterator methods returns a new collection
object and leaves the original object unchanged.
a = ['a', 'b', 'c']
a.reverse # => ["c", "b", "a"]
a # => ["a", "b", "c"]
For every iterator method there is typically an
associated in place method ending in !. The in
place method transforms the collection in place and returns
the result.
a = ['a', 'b', 'c']
a.reverse! # => ["c", "b", "a"]
a # => ["c", "b", "a"]
Ruby Programming
Common Shortcuts
|