What is the purpose of the Enumerator class in Ruby

If I create an Enumertor as follows:

enum = [1,2,3].each => #<Enumerator: [1, 2, 3]:each> 

enum is an enumerator. What is the purpose of this facility? I can not say this:

 enum { |i| puts i } 

But I can say the following:

 enum.each { |i| puts i } 

This seems redundant because the Enumerator was created using .each . It looks like it stores some data regarding the each method.

I don’t understand what is going on here. I am sure there is some logical reason why we have this Enumerator class, but what can it do that Array cannot? I thought maybe it was the ancestor of Array and other Enumerables, but it doesn't seem to be that way. What is the reason for the existence of the Enumerator class and in what context will it ever be used?

+4
source share
4 answers

What happens if you run enum = [1,2,3].each; enum.next enum = [1,2,3].each; enum.next ?:

 enum = [1,2,3].each => #<Enumerator: [1, 2, 3]:each> enum.next => 1 enum.next => 2 enum.next => 3 enum.next StopIteration: iteration reached an end 

This can be useful if you have an Enumerator that performs calculations such as a prime calculator or a Fibonacci sequence generator. It provides flexibility in writing code.

+2
source

I think the main goal is to get items on demand, rather than getting them all in one cycle. I mean something like this:

 e = [1, 2, 3].each ... do stuff ... first = e.next ... do stuff with first ... second = e.next ... do more stuff with second ... 

Note that those parts of do stuff may be in different functions, far from each other.

Lena estimates of infinite sequences (for example, primes, Fibonacci numbers, string keys such as 'a'..'z','aa'..'az','ba'..'zz','aaa'.. etc.) are a good precedent for counters.

+1
source

As already mentioned, Enumerator comes in handy when you want to iterate over a sequence of data of potentially infinite length.

Take prime_generator prime generator, which extends, for example, Enumerator. If we want to get the first 5 primes, we can simply write prime_generator.take 5 instead of inserting a β€œlimit” into the generating logic. Thus, we can separate the generation of primes and take a certain amount from the generated primes, which makes the generator multiple.

I for one, as a method, using Enumerable return Enumerator methods, as in the following example (it may not be a β€œtarget”, but I just want to point out its aesthetic aspect):

 prime_generator.take_while{|p| p < n}.each_cons(2).find_all{|pair| pair[1] - pair[0] == 2} 

Here prime_generator is an instance of Enumerator that returns numbers one by one. We can take primes below n using the take_while method for Enumerable. The methods each_cons and find_all return an Enumerator so that they can be bound. This example is designed to generate double numbers below n . It may be an inefficient implementation, but it is easily written in a string and IMHO suitable for prototyping.

Here is a fairly simple implementation of prime_generator based on Enumerator:

 def prime?(n) n == 2 or (n >= 3 and n.odd? and (3...n).step(2).all?{|k| n%k != 0}) end prime_generator = Enumerator.new do |yielder| n = 1 while true yielder << n if prime? n n += 1 end end 
+1
source

You can combine counters:

 array.each.with_index { |el, idx| ... } 
0
source

Source: https://habr.com/ru/post/1484933/


All Articles