Ruby Logo

Enumerator & Enumerable Mastery

Learn custom enumerators, lazy evaluation, infinite sequences, and the Enumerable module.

Home Ruby Enumerator & Enumerable Mastery

Enumerator & Enumerable Mastery

Enumerators are powerful Ruby objects that provide lazy evaluation, custom iteration, and chaining capabilities. They're essential for memory-efficient processing, infinite sequences, and creating custom iterators. Master the Enumerable module and custom enumerators.

Enumerator Basics & Creation

Enumerators: Enumerators are objects that provide iteration capabilities with lazy evaluation. They allow you to create custom iterators, chain operations, and process data efficiently without loading everything into memory.

Creating Enumerators

# Creating enumerators from existing objects
array = [1, 2, 3, 4, 5]
enum = array.each
puts
enum.class
# Enumerator

# Using Enumerator.new with a block
fib_enum = Enumerator.new do |yielder|
a, b = 0, 1
loop
do
yielder << a
a, b = b, a + b
end
end

puts
fib_enum.take(10)
# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

# Using to_enum method
range_enum = (1..10).to_enum
puts
range_enum.next
# 1
puts
range_enum.next
# 2

Key Feature: Enumerators provide lazy evaluation, meaning they only compute values when needed. This makes them perfect for infinite sequences and memory-efficient processing.

Lazy Evaluation & Infinite Sequences

Lazy Enumerators

# Lazy evaluation with large datasets
numbers = (1..1_000_000).lazy
result = numbers
.select(&:even?)
.map { |x| x * x }
.take(5)

puts
result.to_a
# [4, 16, 36, 64, 100]

# Infinite sequence example
infinite_squares = Enumerator.new do |yielder|
n = 1
loop
do
yielder << n * n
n += 1
end
end

puts
infinite_squares.take(10)
# [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

Custom Infinite Sequences

# Prime numbers enumerator
primes = Enumerator.new do |yielder|
n = 2
loop
do
if (2..Math.sqrt(n)).none? { |i| n % i == 0 }
yielder << n
end
n += 1
end
end

puts
primes.take(10)
# [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]

# Random numbers enumerator
random_numbers = Enumerator.new do |yielder|
loop
do
yielder << rand(1..100)
end
end

puts
random_numbers.take(5)
# [42, 17, 89, 3, 56] (random)

Enumerable Module & Custom Iterators

Making Classes Enumerable

# Custom enumerable class
class
NumberRange
include Enumerable
def initialize(start, stop, step = 1)
@start = start
@stop = stop
@step = step
end
def each
current = @start
while
current <= @stop
yield current
current += @step
end
end
end

range = NumberRange.new(1, 10, 2)
puts
range.to_a
# [1, 3, 5, 7, 9]
puts
range.sum
# 25
puts
range.select(&:odd?)
# [1, 3, 5, 7, 9]

Enumerator Methods

# Enumerator control methods
enum = (1..5).each

# Manual iteration
puts
enum.next
# 1
puts
enum.next
# 2
puts
enum.peek
# 3 (doesn't advance)
puts
enum.next
# 3

# Rewind to beginning
enum.rewind
puts
enum.next
# 1

# Check if enumeration is finished
enum = (1..3).each
enum.next; enum.next; enum.next
puts
enum.next
# raises StopIteration

Interactive Practice: Enumerator & Enumerable

Practice Time: Try these enumerator and enumerable examples and experiment with different lazy evaluation patterns. Understanding these concepts will make you a more effective Ruby programmer.

Interactive Code Runner

Ruby Code Editor
Output will appear here when you run the code...

Enumerator & Enumerable Best Practices

✅ Do This

  • Use lazy enumerators for large datasets
  • Create custom enumerators for infinite sequences
  • Include Enumerable in custom classes
  • Use take() to limit infinite sequences
  • Chain operations for efficient processing

❌ Avoid This

  • Forgetting to use lazy for large datasets
  • Creating infinite loops without take()
  • Not handling StopIteration exceptions
  • Using enumerators when arrays are simpler
  • Ignoring memory implications

Enumerator & Enumerable Mastery Checklist

  • Enumerator Creation: Create enumerators from existing objects and with blocks
  • Lazy Evaluation: Use lazy enumerators for memory-efficient processing
  • Infinite Sequences: Create enumerators for infinite data streams
  • Enumerable Module: Include Enumerable in custom classes
  • Manual Control: Use next, peek, and rewind for manual iteration
  • Chaining: Chain enumerator operations for complex processing
  • Error Handling: Handle StopIteration exceptions properly
  • Performance: Understand when to use lazy vs eager evaluation

Next Steps: Practice with enumerators for infinite sequences, lazy evaluation, and custom iterators. Enumerators are essential for memory-efficient processing and powerful iteration patterns!

Quick Navigation

Related Topics

Video Tutorial

Watch and learn enumerator & enumerable mastery

Pro Tip: After reading through the content above, watch this video to reinforce your understanding and see the concepts in action!