On 27 January 2011 01:42, redstun <redstun / gmail.com> wrote:
> 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 an=
d
> yield the same performance.
>
> The dynamic nature and elegance design of Ruby certainly sacrificed
> performance at somewhat level, but =A0that doesn't stop you and me from u=
sing
> it, right? :-)
>
> Anyway, thanks for the benchmark demo, I just ran it on my machine, with
> both MRI and JRuby,
> MRI 1.8.7
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0user =A0 =
=A0 system =A0 =A0 =A0total =A0 =A0 =A0 =A0real
> each_with_index.inject(0) =A0 4.930000 =A0 0.000000 =A0 4.930000 ( =A05.0=
36288)
> inject(0) =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 3.088000 =A0 0.000000 =A0 3=
.088000 ( =A03.080176)
> each_with_index =A0 =A0 =A0 =A0 =A0 =A0 2.668000 =A0 0.000000 =A0 2.66800=
0 ( =A02.668153)
> each =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A01.700000 =A0 0.000000=
 =A0 1.700000 ( =A01.713098)
>
> JRuby 1.5.6
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0user =A0 =
=A0 system =A0 =A0 =A0total =A0 =A0 =A0 =A0real
> each_with_index.inject(0) =A0 1.918000 =A0 0.000000 =A0 1.918000 ( =A01.9=
18000)
> inject(0) =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 1.058000 =A0 0.000000 =A0 1=
.058000 ( =A01.058000)
> each_with_index =A0 =A0 =A0 =A0 =A0 =A0 0.979000 =A0 0.000000 =A0 0.97900=
0 ( =A00.979000)
> each =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A00.624000 =A0 0.000000=
 =A0 0.624000 ( =A00.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 =3D [3, 4, 5]
>> rrr =3D ary.each_with_index.inject(0) { |sum, (v, index)| sum + v * inde=
x }
>> p rrr #=3D> 14
>> index =3D -1; rrr =3D ary.inject(0) { |sum, v| index +=3D 1; sum + v * i=
ndex }
>> p rrr #=3D> 14
>> rrr =3D 0; ary.each_with_index { |v, index| rrr +=3D v * index }; rrr
>> p rrr #=3D> 14
>> index =3D -1; rrr =3D 0; ary.each { |v| index +=3D 1; rrr +=3D v * index=
 }; rrr
>> p rrr #=3D> 14
>>
>> require "benchmark"
>> kt =3D 500_000
>> Benchmark.bmbm() do |bm|
>> =A0bm.report( "each_with_index.inject(0)" ) { kt.times {
>> =A0 rrr =3D ary.each_with_index.inject(0) { |sum, (v, index)| sum + v * =
index }
>> =A0} }
>> =A0bm.report( "inject(0)" =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ) { kt.times {
>> =A0 index =3D -1; rrr =3D ary.inject(0) { |sum, v| index +=3D 1; sum + v=
 * index }
>> =A0} }
>> =A0bm.report( "each_with_index" =A0 =A0 =A0 =A0 =A0 ) { kt.times {
>> =A0 rrr =3D 0; ary.each_with_index { |v, index| rrr +=3D v * index }
>> =A0} }
>> =A0bm.report( "each" =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0) { kt.t=
imes {
>> =A0 index =3D -1; rrr =3D 0; ary.each { |v| index +=3D 1; rrr +=3D v * i=
ndex }
>> =A0} }
>> end
>>
>> #=3D>
>> Rehearsal -------------------------------------------------------------
>> each_with_index.inject(0) =A0 2.410000 =A0 0.000000 =A0 2.410000 ( =A02.=
404242)
>> inject(0) =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 1.000000 =A0 0.000000 =A0 =
1.000000 ( =A01.000677)
>> each_with_index =A0 =A0 =A0 =A0 =A0 =A0 0.840000 =A0 0.010000 =A0 0.8500=
00 ( =A00.846287)
>> each =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A00.640000 =A0 0.00000=
0 =A0 0.640000 ( =A00.640142)
>> ---------------------------------------------------- total: 4.900000sec
>>
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0user =A0 =
=A0 system =A0 =A0 =A0total =A0 =A0 =A0 =A0real
>> each_with_index.inject(0) =A0 2.380000 =A0 0.020000 =A0 2.400000 ( =A02.=
392590)
>> inject(0) =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 1.000000 =A0 0.000000 =A0 =
1.000000 ( =A00.999785)
>> each_with_index =A0 =A0 =A0 =A0 =A0 =A0 0.850000 =A0 0.000000 =A0 0.8500=
00 ( =A00.846178)
>> each =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A00.640000 =A0 0.00000=
0 =A0 0.640000 ( =A00.639366)
>>
>> (My apologies if the benchmarks are ragged and unaligned.)
>>
>>
>

Just to complete with 1.9 (ruby 1.9.3dev (2011-01-26 trunk 30659)
[x86_64-darwin10.6.0]) results:

Rehearsal -------------------------------------------------------------
each_with_index.inject(0)   1.220000   0.000000   1.220000 (  1.220411)
inject(0)                   0.560000   0.000000   0.560000 (  0.568007)
each_with_index             0.510000   0.010000   0.520000 (  0.516797)
each                        0.400000   0.000000   0.400000 (  0.405471)
---------------------------------------------------- total: 2.700000sec

                                user     system      total        real
each_with_index.inject(0)   1.250000   0.000000   1.250000 (  1.268727)
inject(0)                   0.570000   0.010000   0.580000 (  0.582921)
each_with_index             0.510000   0.000000   0.510000 (  0.510591)
each                        0.390000   0.000000   0.390000 (  0.401833)

Only each_with_index.inject is notably slower, others are similar.