Interesting, thanks Colin.

As you said, the code you demonstrated, could performer better, meanwhile
it's somewhat less elegant.

IMHO the code is ok, we just have more space inside the
interpreter/runtime to get improved, like in JVM, the JIT compiler could
compile all of the 4 lines of code in to the same machine instructions and
yield the same performance.

The dynamic nature and elegance design of Ruby certainly sacrificed
performance at somewhat level, but  that doesn't stop you and me from using
it, right? :-)

Anyway, thanks for the benchmark demo, I just ran it on my machine, with
both MRI and JRuby,
MRI 1.8.7
                                user     system      total        real
each_with_index.inject(0)   4.930000   0.000000   4.930000 (  5.036288)
inject(0)                   3.088000   0.000000   3.088000 (  3.080176)
each_with_index             2.668000   0.000000   2.668000 (  2.668153)
each                        1.700000   0.000000   1.700000 (  1.713098)

JRuby 1.5.6
                                user     system      total        real
each_with_index.inject(0)   1.918000   0.000000   1.918000 (  1.918000)
inject(0)                   1.058000   0.000000   1.058000 (  1.058000)
each_with_index             0.979000   0.000000   0.979000 (  0.979000)
each                        0.624000   0.000000   0.624000 (  0.624000)

Like your result the raw each runs the fastest, but we can also find that,
the result of each_with_index.inject with JRuby is already close to that of
raw each with MRI.


On Tue, Jan 25, 2011 at 5:43 AM, Colin Bartlett <colinb2r / googlemail.com>wrote:

> I'm curious as to when and why people use each_with_index and/or
> inject, etc, instead of a somewhat less elegant, and admittedly
> possibly less flexible, more direct approach. (Which usually(?) takes
> about the same number of characters for the code.)
>
> ary = [3, 4, 5]
> rrr = ary.each_with_index.inject(0) { |sum, (v, index)| sum + v * index }
> p rrr #=> 14
> index = -1; rrr = ary.inject(0) { |sum, v| index += 1; sum + v * index }
> p rrr #=> 14
> rrr = 0; ary.each_with_index { |v, index| rrr += v * index }; rrr
> p rrr #=> 14
> index = -1; rrr = 0; ary.each { |v| index += 1; rrr += v * index }; rrr
> p rrr #=> 14
>
> require "benchmark"
> kt = 500_000
> Benchmark.bmbm() do |bm|
>  bm.report( "each_with_index.inject(0)" ) { kt.times {
>   rrr = ary.each_with_index.inject(0) { |sum, (v, index)| sum + v * index }
>  } }
>  bm.report( "inject(0)"                 ) { kt.times {
>   index = -1; rrr = ary.inject(0) { |sum, v| index += 1; sum + v * index }
>  } }
>  bm.report( "each_with_index"           ) { kt.times {
>   rrr = 0; ary.each_with_index { |v, index| rrr += v * index }
>  } }
>  bm.report( "each"                      ) { kt.times {
>   index = -1; rrr = 0; ary.each { |v| index += 1; rrr += v * index }
>  } }
> end
>
> #=>
> Rehearsal -------------------------------------------------------------
> each_with_index.inject(0)   2.410000   0.000000   2.410000 (  2.404242)
> inject(0)                   1.000000   0.000000   1.000000 (  1.000677)
> each_with_index             0.840000   0.010000   0.850000 (  0.846287)
> each                        0.640000   0.000000   0.640000 (  0.640142)
> ---------------------------------------------------- total: 4.900000sec
>
>                                user     system      total        real
> each_with_index.inject(0)   2.380000   0.020000   2.400000 (  2.392590)
> inject(0)                   1.000000   0.000000   1.000000 (  0.999785)
> each_with_index             0.850000   0.000000   0.850000 (  0.846178)
> each                        0.640000   0.000000   0.640000 (  0.639366)
>
> (My apologies if the benchmarks are ragged and unaligned.)
>
>