Ruby: Inject for Enumerable Lazy

Being a declarative language, ruby provides many functions which make developer lives easier. One of those functions is Enumerable#inject.

This function iterates through elements of an Enumerable by applying an operation represented by a block (or a symbol which represents a method defined on elements of the enumerable).

Example:

(1..10).inject(:+)
# returns 55

The above function calls + method on the accumulator and the next element of the list, which further sets it to the next iteration’s accumulator. Hence, we get the sum for first 10 numbers, 55.

Lazy with INFINITY stream

In order to call the inject with a stream of integers, we can use Float::INFINITY with Enumerator::Lazy.

(1..Float::INFINITY).lazy.first(10).inject(:+)

This allows us to call first with an integer which gets the first few elements from the infinite stream of integers, which forms an array, which then applies the inject operation on it’s elements.

For Fun: Enumerator::Lazy#inject/3

Another way to accomplsh the above functionality is by creating a method inject which is called with three arguments: acc: Initial value of the accumulator. first: First first number of elements to take from the lazy. &block: Operation represented by a block.

# Opening up Enumerator::Lazy class
class Enumerator::Lazy
  def inject(acc, first, &block)
    @acc = acc

    Lazy.new(self) do |yielder, *result|
      @acc = yield [*result, @acc]
      yielder << @acc
    end.first(first).last
  end
end

(1..Float::INFINITY).lazy.inject(0, 10) { |a, b| a + b }
# returns 55

This defines a method, inject for Enumerator::Lazy, which allows us to call inject with the first argument.

This functionality can be extended to other Enumerable operations like each and each_with_index