Ruby Enumerators
Powerful iteration and collection processing in Ruby
🔄 What are Enumerators?
Enumerators are objects that allow you to iterate over collections in a controlled way. They provide lazy evaluation and chainable methods for efficient data processing without loading everything into memory.
# Basic enumerator
enum = [1, 2, 3].each
puts enum.next
puts enum.next
Output:
1
2
Key Enumerator Concepts
Next Method
Get the next element
enum.next
Rewind
Reset to the beginning
enum.rewind
Chaining
Combine multiple operations
enum.map.with_index
Lazy Evaluation
Process data on demand
(1..Float::INFINITY).lazy
🔹 Creating Enumerators
You can create enumerators from arrays, ranges, or any enumerable object. Enumerators give you fine control over iteration, allowing you to pause and resume as needed.
# Create enumerator from array
numbers = [10, 20, 30, 40]
enum = numbers.each
puts enum.next # 10
puts enum.next # 20
enum.rewind
puts enum.next # 10 (back to start)
Output:
10
20
10
🔹 Enumerator with Index
Track both the element and its position during iteration. The with_index method adds an index counter to your enumeration, perfect for numbered lists or position-aware processing.
# Enumerate with index
fruits = ["apple", "banana", "cherry"]
fruits.each.with_index do |fruit, index|
puts "#{index + 1}. #{fruit}"
end
Output:
1. apple
2. banana
3. cherry
🔹 Lazy Enumerators
Lazy enumerators process elements only when needed, making them perfect for large or infinite sequences. They don't compute all values upfront, saving memory and improving performance for big datasets.
# Lazy evaluation for efficiency
numbers = (1..Float::INFINITY).lazy
.select { |n| n % 2 == 0 }
.map { |n| n * 2 }
.first(5)
puts numbers.inspect
Output:
[4, 8, 12, 16, 20]
🔹 Custom Enumerators
Build your own enumerators using Enumerator.new with a block. This lets you define custom iteration logic for any data source or pattern you need.
# Create custom enumerator
fibonacci = Enumerator.new do |yielder|
a, b = 0, 1
loop do
yielder << a
a, b = b, a + b
end
end
puts fibonacci.first(7).inspect
Output:
[0, 1, 1, 2, 3, 5, 8]
🔹 Enumerator Chaining
Combine multiple enumerator methods to create powerful data processing pipelines. Chaining allows you to filter, transform, and manipulate data in a clean, readable way.
# Chain multiple operations
result = [1, 2, 3, 4, 5, 6]
.each
.select { |n| n.even? }
.map { |n| n ** 2 }
.to_a
puts result.inspect
Output:
[4, 16, 36]
🔹 Practical Enumerator Example
Process a large file line by line without loading it all into memory. This demonstrates how enumerators excel at handling large datasets efficiently by processing one item at a time.
# Simulate reading large file
lines = ["Line 1", "Line 2", "Line 3", "Line 4", "Line 5"]
enum = lines.each
# Process one line at a time
3.times do
begin
line = enum.next
puts "Processing: #{line}"
rescue StopIteration
puts "No more lines"
break
end
end
Output:
Processing: Line 1
Processing: Line 2
Processing: Line 3