Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement an enumerator in Ruby?

For example:

a = [1,2,3,4,5]
a.delete_if { |x| x > 3 }

is equivalent to:

a = [1,2,3,4,5]
a.delete_if.each.each.each.each { |x| x > 3 }

I know a.delete_if returns an enumerator. But how does it know it should delete object when the each block returns true? How to implement delete_if by hand(and in Ruby)?

like image 978
Lai Yu-Hsuan Avatar asked Oct 07 '11 19:10

Lai Yu-Hsuan


People also ask

What is an enumerator in Ruby?

Enumerator, specifically, is a class in Ruby that allows both types of iterations – external and internal. Internal iteration refers to the form of iteration which is controlled by the class in question, while external iteration means that the environment or the client controls the way iteration is performed.

What does the lazy method do to enumerators?

Enumerator::Lazy. Enumerator::Lazy is a special type of Enumerator , that allows constructing chains of operations without evaluating them immediately, and evaluating values on as-needed basis. In order to do so it redefines most of Enumerable methods so that they just construct another lazy enumerator.

How do you add to an array in Ruby?

push() is a Ruby array method that is used to add elements at the end of an array. This method returns the array itself.

Is an array an enumerable Ruby?

Some Ruby classes include Enumerable: Array. Dir. Hash.


2 Answers

You can take a look at the Rubinius source code: enumerable module

Here an example of the reject method:

  def reject
    return to_enum(:reject) unless block_given?

    ary = []
    each do |o|
      ary << o unless yield(o)
    end

    ary
  end
like image 104
topek Avatar answered Sep 28 '22 12:09

topek


In the implementation of delete_if, the code can verify the value returned from yield to decide whether or not to delete the given entry from the array.

You can read Implementing Iterators in the Programming Ruby guide for more details, but it would looks something like:

class Array
  def delete_if
     reject { |i| yield i }.to_a
  end
end

The above uses yield to pass each item in the array to the block associated with the call to delete_if, and implicitly returns the value of the yield to the outer reject call.

like image 42
Pete Avatar answered Sep 28 '22 13:09

Pete