Enumerators

External iteration

Calling each without a block returns an Enumerator, which is an iterator you drive by hand.

Each next call returns the following element, which helps when input arrives in steps.

enum = [1, 2, 3].each puts enum.next puts enum.next

ruby enum_demo.rb

1
2

Lazy chains

Long or endless sequences need lazy chains, so values are computed only on demand.

The lazy call turns the endless range into a lazy enumerator, and first pulls just five doubled values.

result = (1..).lazy.map { |n| n * 2 }.first(5) p result

ruby lazy_demo.rb

[2, 4, 6, 8, 10]

each_with_object

The each_with_object method folds a collection into a memo object that the block mutates.

A hash with default zero counts letters without any key checks.

counts = ["a", "b", "a"].each_with_object(Hash.new(0)) do |letter, memo| memo[letter] += 1 end p counts

ruby counts_demo.rb

{"a" => 2, "b" => 1}

A Fibonacci enumerator

Custom sequences come from Enumerator.new with a block that yields each value.

An endless loop is safe here because first stops the sequence after six numbers.

fib = Enumerator.new do |y| a = 0 b = 1 loop do y << a a, b = b, a + b end end puts fib.first(6).inspect

ruby fib_demo.rb

[0, 1, 1, 2, 3, 5]

Next: The array toolbox

Article author: Arthur Isaev