The concept of iterator is implemented, in Ruby, by the Enumerator class, most iterator methods return an object of this class.
An Enumerator has the method to_a to produce an array, the method next to extract (and delete) an element, a method peek to fetch the current value (without deletion), a method rewind to begin again the sequence and a method each that loops over the elements giving them, in turn, to a block:
a=Enumerator.new([1,2,3]) a.each {|k| print k} => 123 a.next => 1 a.next => 2 # extract, and consume the element a.peek => 3 # only fetch the current element a.peek => 3 # always the same element without a "*next*" a.next => 3 a.next => raise a StopIteration exception a.rewind # to begin again the sequence a.next => 1
Most iterators are implemented in the Enumerable module; this module is mixed into classes which contain sequences: Array, Hashes, Range, Struct, IO and Dir; since Ruby 1.9 the class String doesn't use the Enumerable module but implements all its own iterators.
Some member of the module Enumerable are listed in the following table:
all? | true if all the elements are true. Es.: [0,true,nil].all? => false |
any? | true if some elements is true. Es.: [0,true,nil].any? => true |
collect ; map | array obtained by the block: (1..2).collect {|a| a*2} => [2, 4] |
count | counts true values from block: (1..6).count {|a| a<3 } => 2 |
cycle(n) | cycles n time over the sequence: [1,2].cycle(2) {|a| print a} => 1212 |
detect | return the first true element: (1..6).detect {|a| a>3 } => 4 |
drop(n) | array without the first n elements: [1,2,3,4].drop(2) => [3, 4] |
drop_wile | drops until block returns true: [1,2,3,4].drop_while {|a| a < 3 } => [3, 4] |
take_while | take until block returns false: [1,2,3,4].take_while {|a| a < 3 } => [1, 2] |
each_slice(n) | loops on groups of n values:(1..4).each_slice(2){|a| print a}=>[1,2][3,4] |
each_with_index | value and index to the loop:(1..3).each_with_index{|a,i| print a,i}=>102132 |
find_all ; select | all elements for which the block is true: (1..3).find_all {|a| a>1}=>[2, 3] |
reject | all elements for which the block is false: (1..3).reject {|a| a>1} => [1] |
find_index | index of first element giving a true block: (1..3).find_index{|a| a>1} => 1 |
first(n);take(n) | first n elements: (1..4).first(2) => [1, 2] |
grep(pattern) | array of matching elements:["a","b","c"].grep(/b|c/){|i| i}=>["b","c"] |
include? | true if an element is included: (1..3).include? => true |
max | maximum value: (1..3).max => 3 |
min | minimum value: `` (1..3).min => 1 `` |
max_by | value giving the greater block: (1..3).max_by {|a| 1.0/a } => 1 |
min_by | value giving the smaller block: (1..3).min_by {|a| 1.0/a } => 3 |
minmax | minimum and maximum value (1..3).minmax => [1, 3] |
one? | true if the block return true only once: (1..3).one? {|a| a==2 } => true |
none? | true if the block is always false (1..3).none? {|a| a==2 }=> false |
reverse_each | loops in reverse order: (1..3).reverse_each {|a| print a } => 321 |
sort | sort elements: [3,2,1].sort => [1, 2, 3] |
sort_by | sorting based on the block: (1..3).sort_by {|a| 1.0/a } => [3, 2, 1] |
flat_map can be used to build an array, by appending consecutive results of the block:
(1..2).flat_map{|a| [a,a+10,a+20]} => [1, 11, 21, 2, 12, 22]
group_by can be used to build an hash, the block gives the keys:
(1..3).group_by { |a| a+100 } => {101=>[1], 102=>[2], 103=>[3]}
minmax can have an associated block, giving a comparison expression which utilized the "<=>" operator;
also sort can have an associated block:
(1..3).minmax {|a,b| 1.0/a <=> 1.0/b } => [3, 1] (1..3).sort {|a,b| 1.0/a <=> 1.0/b } => [3, 2, 1]
upto | 3.upto(5) {|i| print i, " " } => 3 4 5 (last value is included ) |
downto | 3.downto(1) {|n| print n, ".. " } => 3.. 2.. 1.. |
times | 3.times {|n| print n, ".. " } => 0.. 1.. 2.. |
step | 1.step(6, 2) {|i| print i, " " } => 1 3 5 |
If the block is missing these methods return an Enumerator object which can be converted to an array with the to_a method
3.upto(5).to_a => [3, 4, 5] 3.downto(1).to_a => [3, 2, 1] 3.times.to_a => [0, 1, 2] 1.step(6, 2).to_a => [1, 3, 5] 12.2.step(14.0,0.5).to_a => [12.2, 12.7, 13.2, 13.7]
each_char | loops on characters: "abcd".each_char {|k| print k+"z" }azbzczdz=> "abcd" |
each_byte;bytes | loops on bytes: "abcd".each_byte {|k| print k,"-" } => 97-98-99-100- |
eachy_line | loops on lines (keep the final "n" characters) |
upto | loops on a sequence of strings: "a".upto("d"){|k| print k} => abcd |
Also these methods, if the block is not present, return an iterator which can be converted to an array.
each | gives each item to the block: [1,2,3].each {|k| print k} => 123 |
reverse_each | gives items in reverse order: [1,2,3].each {|k| print k} => 123 |
each_index | gives indexes to the block: [1,2,3].each_index {|k| print k} => 012 |
map | array with block results: [1,2,3].map {|k| k+1} => [2,3,4] |
collect;collect! | array of block results: [1,2,3].collect {|i| i*i } => [1, 4, 9] |
delete_if | if block false deletes elements: [1,2,3].delete_if {|x| x.even?} => [1, 3] |
keep_if | keeps if block true: [1,2,3].keep_if { |x| x.even? } => [2] |
select;select! | elements with a true block: [1,2,3].select { |x| x.even? } => [2] |
rindex | index of element of first true block: [1,2,3].rindex {|k| k==2}=> 1 |
uniq ; uniq! | elements with unique block value: [1,2,3,4].uniq {|k| k.even?}=> [1,2] |
The creator of arrays can also be used as an iterator:
a=Array.new(3) { |i| i} => [0, 1, 2]
Hashes has iterators similar to the iterators for arrays, but give different arguments to the block:
each ; each_pair | gives each pair key,value {1=>"a",2=>"b"}.each {|k,v| print k,v} => 1a2b |
each_key | gives the keys to the block: {1=>"a",2=>"b"}.each_key {|k| print k} =>12 |
each_value | gives the values to the block: {1=>"a",2=>"b"}.each_value{|k| print k} =>ab |
delete_if | if block false deletes: {1=>"a",2=>"b"}.delete_if {|k,v| k==1 => {2=>"b"} |
keep_if | keeps if block true: {1=>"a",2=>"b"}.keep_if {|k,v| k==1 } => {1=>"a"} |
select,select! | hash of elements with true block: {1=>"a",2=>"b"}.select {|k,v| k==1}{1=>"a"} |
The merge method can be used associated with a block: when there are duplicated keys the block is executed and the new value for the key is the the block result
{1=>"a",2=>"b"}.merge({1=>"x",3=>"z"}) {|key,v1,v2| v1+v2 } => {1=>"ax", 2=>"b", 3=>"z"}