What is the difference between the enumerators returned by the enumerable methods when no block is given?

ary = [1, 2, nil, 4]
enu1 = ary.find
enu2 = ary.filter
enu3 = ary.map
[enu1.next, enu1.next, enu1.next, enu1.next]
[enu2.next, enu2.next, enu2.next, enu2.next]
[enu3.next, enu3.next, enu3.next, enu3.next]

The previous 3 arrays are the same.

So, what is there a reason for choosing one method over the other?

If you don’t give a block, they each return an enumerator - see the documentation module Enumerable - RDoc Documentation

The enumerator can be used to do the original task of the method by using each, so each of your enu values is different.

2.7.2 :019 > ary
 => [1, 2, nil, 4] 
2.7.2 :020 > ary.filter {|i| i && i%2 == 0}
 => [2, 4] 
2.7.2 :021 > enu2 = ary.filter
 => #<Enumerator: [1, 2, nil, 4]:filter> 
2.7.2 :022 > enu2.each {|i| i && i%2 == 0}
 => [2, 4] 
2.7.2 :023 > enu3 = ary.map
 => #<Enumerator: [1, 2, nil, 4]:map> 
2.7.2 :024 > enu3.each {|i| i && i%2 == 0}
 => [false, true, nil, true] 

Notice how using enu2 applies filter, but using enu3 applies map. This in spite of each being called using each and the same block.

2 Likes

Thank you.

This is the first time I see this way of using the enumerators. The documentation mentions that with no block, an enumerator is returned, but there is not a single example of how to use those enumerators.

Thank you very much!

So, to activate the task of “filter”, “find”, “map”, or whatever method was used to create the enumerator, we have to use each with block. Is that the only interface? I suppose we could use each_with_index, or with_object (which is a reduce). What happens with reduce then?

Thanks to @pcl I understand the difference between enumerators returned by different Enumerable methods.

But now, I’m wondering how this style is used in real life.

Anybody knows in what situations those enumerators extracted from the Enumerable methods called without block are used, or does anybody uses in it’s code?