#inject and slowness

I've often heard Ruby's inject method criticized as being "slow." As I rather like the function, and see equivalents in other languages, I'm curious if it's merely Ruby's implementation of the method that's slow, or if it is inherently a slow way to do things (e.g. should be avoided for non-small collections)?

Answers


inject is like fold, and can be very efficient in other languages, fold_left specifically, since it's tail-recursive.


It's mostly an implementation issue, but this gives you a good idea of the comparison:

$ ruby -v
ruby 1.8.7 (2008-08-11 patchlevel 72) [i486-linux]
$ ruby exp/each_v_inject.rb 
Rehearsal -----------------------------------------------------
loop                0.000000   0.000000   0.000000 (  0.000178)
fixnums each        0.790000   0.280000   1.070000 (  1.078589)
fixnums each add    1.010000   0.290000   1.300000 (  1.297733)
Enumerable#inject   1.900000   0.430000   2.330000 (  2.330083)
-------------------------------------------- total: 4.700000sec

                        user     system      total        real
loop                0.000000   0.000000   0.000000 (  0.000178)
fixnums each        0.760000   0.300000   1.060000 (  1.079252)
fixnums each add    1.030000   0.280000   1.310000 (  1.305888)
Enumerable#inject   1.850000   0.490000   2.340000 (  2.340341)

exp/each_v_inject.rb

require 'benchmark'

total = (ENV['TOTAL'] || 1_000).to_i
fixnums = Array.new(total) {|x| x}

Benchmark.bmbm do |x|
  x.report("loop") do
    total.times { }
  end

  x.report("fixnums each") do
    total.times do |i|
      fixnums.each {|x| x}
    end
  end

  x.report("fixnums each add") do
    total.times do |i|
      v = 0
      fixnums.each {|x| v += x}
    end
  end    

  x.report("Enumerable#inject") do
    total.times do |i|
      fixnums.inject(0) {|a,x| a + x }
    end
  end  
end

So yes it is slow, but as improvements occur in the implementation it should become a non-issue. There is nothing inherent about WHAT it is doing that requires it to be slower.


each_with_object may be faster than inject, if you're mutating an existing object rather than creating a new object in each block.


Need Your Help

A useful metric for determining when the JVM is about to get into memory/GC trouble

java scala garbage-collection jvm

I have a scala data processing application that 95% of the time can handle the data thrown at it in memory. The remaining 5% if left unchecked doesn't usually hit OutOfMemoryError, but just gets in...

Html helper for <input type="file" />

asp.net-mvc razor file-upload upload

Is there a HTMLHelper for file upload? Specifically, I am looking for a replace of