Enumerable.inject_with_index?

Enumerable.inject is pretty cool, but it treat the elements as if they have
the same weight when doing the calculation, in my case I need to apply a
different weight based on the index of each element, therefore I also need
the index being provided as one more block parameter.

enum.find_index might help, but I think there should be a more direct way to
get the index.

In short, like for enum.each_entry, there's each_with_index,
similarly, for enum.inject, is it possible to have enum.inject_with_index {

memo, obj, index| ... } ?

Thanks

how about,

  (0..5).each.with_index.inject(0){|sum,(i,j)| sum+j}
  #=> 15

  (0..5).each.with_index.inject(0){|sum,(i,j)| sum+i*j}
  #=> 55

best regards -botp

···

On Sun, Jan 23, 2011 at 10:31 PM, redstun <redstun@gmail.com> wrote:

Enumerable.inject is pretty cool, but it treat the elements as if they have
the same weight when doing the calculation, in my case I need to apply a
different weight based on the index of each element, therefore I also need
the index being provided as one more block parameter.
enum.find_index might help, but I think there should be a more direct way to
get the index.
In short, like for enum.each_entry, there's each_with_index,
similarly, for enum.inject, is it possible to have enum.inject_with_index {
>memo, obj, index| ... } ?

sorry if that wasn't so clear. again,

  (3..5).each.with_index.inject(0){|sum,(value,index)| sum+value}
  #=> 12

  (3..5).each.with_index.inject(0){|sum,(value,index)| sum+index}
  #=> 3

  (3..5).each.with_index.inject(0){|sum,(value,index)| sum+index*value}
  #=> 14

kind regards -botp

···

On Sun, Jan 23, 2011 at 11:00 PM, botp <botpena@gmail.com> wrote:

(0..5).each.with_index.inject(0){|sum,(i,j)| sum+j}
#=> 15
(0..5).each.with_index.inject(0){|sum,(i,j)| sum+i*j}
#=> 55

Cool! thanks!

I was working with array, so I can write
[3, 4, 5].each_with_index.inject(0) { |sum, (value, index)| sum + value *
index } #=> 14

OR
ary = [3, 4, 5]
ary.each_index.inject(0) { |sum, index| sum + ary[index] * index } #=> 14

works like a charm :slight_smile:

botp, Thank you very much!

BTW, one more finding is that,
puts([3, 4, 5].each_with_index.inject(0) do |sum, (value, index)| sum +
value * index end)
puts([3, 4, 5].each_with_index.inject(0) { |sum, (value, index)| sum + value
* index })
puts [3, 4, 5].each_with_index.inject(0) { |sum, (value, index)| sum + value
* index }
puts [3, 4, 5].each_with_index.inject(0) do |sum, (value, index)| sum +
value * index end

all works but the last one, it reports TypeError: 0 is not a symbol,
actually caused by the block being passed to puts instead of inject, then
without a block, inject expect a symbol as argument. hum, just a note to
myself.

···

On Sun, Jan 23, 2011 at 11:10 PM, botp <botpena@gmail.com> wrote:

On Sun, Jan 23, 2011 at 11:00 PM, botp <botpena@gmail.com> wrote:
> (0..5).each.with_index.inject(0){|sum,(i,j)| sum+j}
> #=> 15
> (0..5).each.with_index.inject(0){|sum,(i,j)| sum+i*j}
> #=> 55

sorry if that wasn't so clear. again,

(3..5).each.with_index.inject(0){|sum,(value,index)| sum+value}
#=> 12

(3..5).each.with_index.inject(0){|sum,(value,index)| sum+index}
#=> 3

(3..5).each.with_index.inject(0){|sum,(value,index)| sum+index*value}
#=> 14

kind regards -botp

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.)

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? :slight_smile:

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.)

Colin Bartlett wrote in post #977259:

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.

I think you answered it yourself: people will generally choose the more
elegant and/or clearer solution (by their own assessment of 'clearer').

Unless this is the innermost loop of a program which processes a large
dataset, and you've used a profiler to prove that this is the hotspot in
your particular application, the performance difference doesn't matter a
hoot.

···

--
Posted via http://www.ruby-forum.com/\.

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.

···

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 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? :slight_smile:

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.)

guess we find a spot to improve when chaining up multiple enum methods?

btw, looks like you guys both have more powerful computer than mine. :wink:

···

On Thu, Jan 27, 2011 at 9:10 PM, Benoit Daloze <eregontp@gmail.com> wrote:

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
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? :slight_smile:
>
> 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.)
>>
>>
>

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.