2

I learning ruby.

I want to know the difference between enumerable and iterator methods in ruby, and why we use enumerator methods..

to me both looks same.

I want to know the difference between the two

normal iterator method

3.times do
|x| puts x
end

using enumerator each

enumerator = 3.times
enumerator.each do
|x| puts x
end

also for string

"scriptkiddie".each_char{|x| puts x}

using enumerator object

"scriptkiddie".enum_for(:each_char).each{|x| puts x}

What is the benefit of using enumerator. where should I use Enumerator?

Please help me understand the difference

scriptkiddie1
  • 497
  • 2
  • 6
  • 17

1 Answers1

6

Answer to your original question

[1,2,3].each.is_a?(Enumerable)
#=> true
[1,2,3].each.is_a?(Enumerator)
#=> true
[1,2,3].each.class.ancestors
#=> [Enumerator, Enumerable, Object, Kernel, BasicObject]

Yes, the "iterator" each returns an Enumerator when no block is used.

But if you're just learning Ruby and want to iterate over an Array/Range/Hash, just know that using each will cover most of your cases :

[1, 2, 3].each do |element|
  puts element
end
# 1
# 2
# 3

('a'..'e').each do |element|
  puts element
end
# a
# b
# c
# d
# e

{'a' => 1, 'b' => 2}.each do |key, value|
  puts key
  puts value
end
# a
# 1
# b
# 2

At your level, you shouldn't have to care where those methods are defined, for which class or module or how they're called.

Finally, for loops shouldn't be used in Ruby because they can show weird behaviours.

Your updated question

It's good that you made your question clearer. Note that the change might go unnoticed though, especially if you already accepted an answer.

3.times

3.times do |x|
  puts x
end

enumerator = 3.times
enumerator.each do |x|
  puts x
end

Used like this, both are perfectly equivalent. Since the second one is more verbose and enumerator probably isn't used anywhere else, there's no reason to use the second variant. enumerator is longer than 3.times anyway :)

Note that |x| should be on the same line as the block start. Rubocop could help you.

each_char

"scriptkiddie".each_char{|x| puts x}
"scriptkiddie".enum_for(:each_char).each{|x| puts x}

Again, no reason to use the 2nd variant if all you do is create an Enumerator and call each directly on it.

Why use Enumerator?

Chaining methods

One reason to use an Enumerator is to be able to chain Enumerable methods :

puts 3.times.cycle.first(7)
#=> [0, 1, 2, 0, 1, 2, 0]

or

"script".each_char.with_index{|c, i|
  puts "letter #{i} : #{c}"
}
# letter 0 : s
# letter 1 : c
# letter 2 : r
# letter 3 : i
# letter 4 : p
# letter 5 : t

Infinite lists

Enumerators also make it possible to work with infinite lists.

require 'prime'

every_prime = Prime.each
p every_prime.first(20)
#=> [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71]

p every_prime.lazy.select{|x| x > 1000}.first(3)
#=> [1009, 1013, 1019]

Custom iteration

It's possible to define new Enumerators for custom iterations :

require 'date'

def future_working_days(start_date = Date.today)
  date = start_date
  Enumerator.new do |yielder|
    loop do
      date += 1
      yielder << date unless date.saturday? || date.sunday?
    end
  end
end

puts future_working_days.take(3)
# 2017-02-01
# 2017-02-02
# 2017-02-03
Community
  • 1
  • 1
Eric Duminil
  • 52,989
  • 9
  • 71
  • 124
  • 3
    Technically that's an `Enumerator`, and one of the ancestors is `Enumerable`. – tadman Jan 31 '17 at 09:00
  • 3
    @scriptkiddie1 There is no "Iterator" class in Ruby. An iterator is just a concept, Enumerator is the implementation of one. – tadman Jan 31 '17 at 09:03
  • @tadman thank you bro, I thought iterator is a class and each.. are methods of iterator – scriptkiddie1 Jan 31 '17 at 09:10
  • "At your level" — answers should not be targeted at the OPs level only, Stackoverflow is meant to be a reference book for all programmers that google for this question. This answer does not explain tradeoffs between the two approaches and does not not give an example of when using an enumerator would be justified. – akuhn Jan 31 '17 at 17:29
  • @akuhn : Thanks for at least explaining why you downvoted. It might be a bit unfair though, since the question has been completely changed 4h after my answer got accepted. AFAIK, no notification is sent in this case. – Eric Duminil Jan 31 '17 at 17:47
  • 2
    Excellent answer. Above and beyond! – akuhn Feb 01 '17 at 06:10
  • @Eric Duminil sorry bro, I have edited my question because some people have put my question on hold saying that the question is not clear, so I changed it to be clearer. – scriptkiddie1 Feb 01 '17 at 06:19