Enumerable.inject_with_index?

R

redstun

[Note: parts of this message were removed to make it a legal post.]

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
 
B

botp

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| ... } ?

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
 
B

botp

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

sorry if that wasn't so clear. again,

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

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

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

kind regards -botp
 
R

redstun

[Note: parts of this message were removed to make it a legal post.]

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

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

Colin Bartlett

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

redstun

[Note: parts of this message were removed to make it a legal post.]

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.


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

Brian Candler

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

Benoit Daloze

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.


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

redstun

[Note: parts of this message were removed to make it a legal post.]

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


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.


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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,175
Latest member
Vinay Kumar_ Nevatia
Top