A companion to Enumerable#inject : Enumerable#build

Posted by collin
on Tuesday, August 19

This was a patch idea I had for Rails. Enumerable#inject is great, but there is a little extra bit of code cruft that I see popping up everywhere with regards to using #inject to create a new array or hash. Since the return value of the block passed into #inject becomes the next value of the accumulator, you often see this:

result = (1..10).inject([]) do |array, element|
  array << element if element % 2 == 0
  array
end

puts result.inspect # => [2, 4, 6, 8, 10]

I’d like to see another method added to Enumerable, something like:

module Enumerable

  def build(accumulator)
    each do |item|
      if result = yield(accumulator, item)
        accumulator = result
      end
    end
    accumulator
  end

end

The #build method would essentially reassign the accumulator only if the return value of #yield was non-false. This would shorten the above example into:

result = (1..10).build([]) do |array, element|
  array << element if element % 2 == 0
end

puts result.inspect # => [2, 4, 6, 8, 10]

So yes, one line of savings, but I feel the meaning here is much more clear than the first case using #inject.