Array inject function problem

Hello Rubyists,
I am new to the language and the community.
My first problem is this :

i used the following code :

sum = 0
[1,3,5].inject() {|sum, element| sum + element}
print sum

I expected to get 9
but instead i get 4

I just installed the Ruby 1.8.6 one-click installer on windows
and wrote the above commands in SciTE.
Any suggestions??

···

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

You're confused with how variables work in Ruby

puts [1,3,5].inject() {|sum, element| sum + element} # => 9

'sum' in the block is a different scope from your outside 'sum'

Jason

···

On Fri, Apr 25, 2008 at 11:32 AM, Inbroker Adams <dadravu@yahoo.gr> wrote:

Hello Rubyists,
I am new to the language and the community.
My first problem is this :

i used the following code :

sum = 0
[1,3,5].inject() {|sum, element| sum + element}
print sum

I expected to get 9
but instead i get 4

I just installed the Ruby 1.8.6 one-click installer on windows
and wrote the above commands in SciTE.
Any suggestions??

Inbroker Adams wrote:

Hello Rubyists,
I am new to the language and the community.
My first problem is this :

i used the following code :

sum = 0
[1,3,5].inject() {|sum, element| sum + element}
print sum

I expected to get 9
but instead i get 4

I just installed the Ruby 1.8.6 one-click installer on windows
and wrote the above commands in SciTE.
Any suggestions??

Don't ever use inject--forget you ever read about it. Use a hand
written loop of your own instead. Your code will be easier to
understand and it will be more efficient.

···

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

Actually, in Ruby 1.8 the block variable sum "uses" the existing sum in the outer scope. (Ruby 1.9 will change this.) When the block is executed for the last time, sum is assigned 4 and element 5. The + gives a value of 9, but the block isn't executed after that to assign to sum again.

You probably want the slightly changed:

sum = [1,3,5].inject(0) {|s,e| s+e}
puts sum

-Rob

Rob Biedenharn http://agileconsultingllc.com
Rob@AgileConsultingLLC.com

···

On Apr 25, 2008, at 11:37 AM, Jason Roelofs wrote:

On Fri, Apr 25, 2008 at 11:32 AM, Inbroker Adams <dadravu@yahoo.gr> > wrote:

Hello Rubyists,
I am new to the language and the community.
My first problem is this :

i used the following code :

sum = 0
[1,3,5].inject() {|sum, element| sum + element}
print sum

I expected to get 9
but instead i get 4

I just installed the Ruby 1.8.6 one-click installer on windows
and wrote the above commands in SciTE.
Any suggestions??

You're confused with how variables work in Ruby

puts [1,3,5].inject() {|sum, element| sum + element} # => 9

'sum' in the block is a different scope from your outside 'sum'

Jason

That's not true, at least with ruby 1.8:

sum = 0
[1,3,5].inject() {|sum, element| sum += element}
print sum
=> 9

In ruby 1.8, if a variable with the same name as a block argument exists, it's
used in place of the block variable. This changed in ruby 1.9, where a new
variable is always created, shadowing the one outside the block, as you
stated.

To understand why

print sum

prints 4, it's necessary to understand how exactly inject works:
1) the accumulator (the first block parameter) is set either to the argument
to inject or, if it's not given (as in this case) to the first argument of
the array
2) for each element of the array (except the first, if no argument was given),
the block is called and the accumulator is set to the value returned by the
block. I guess this doesn't happen for the last element: in this case, instead
of setting the accumulator to the return value of the block, inject simply
returns that value.

Usually, the accumulator is a block-local variable, and so it's discarded
after inject returns. In this case, instead, it's a local variable created
outside the block. When inject changes the accumulator, it changes that local
variable, and this is the reason it returns 4.

The correct way to use inject is to use its return value, not it's
accumulator:

res = [1,2,3].inject(){|sum, element| sum + element}
print res

I hope this helps

Stefano

···

On Friday 25 April 2008, Jason Roelofs wrote:

On Fri, Apr 25, 2008 at 11:32 AM, Inbroker Adams <dadravu@yahoo.gr> wrote:
> Hello Rubyists,
> I am new to the language and the community.
> My first problem is this :
>
> i used the following code :
>
> sum = 0
> [1,3,5].inject() {|sum, element| sum + element}
> print sum
>
>
> I expected to get 9
> but instead i get 4
>
> I just installed the Ruby 1.8.6 one-click installer on windows
> and wrote the above commands in SciTE.
> Any suggestions??

You're confused with how variables work in Ruby

puts [1,3,5].inject() {|sum, element| sum + element} # => 9

'sum' in the block is a different scope from your outside 'sum'

Jason

This is the case in Ruby 1.9, and if it were the case here, he'd get 0,
not 4. He's using 1.8, where sum in the block *is* the same sum as
outside the block, so let's look at how this works.

sum=0
simple enough. this could easily be done without (since it will
just be overwritten), but then sum wouldn't be accessable outside
the block.

[1,3,5].inject() {|sum, element| sum + element}

inject calls: yield 1,3
so the block runs assigning the variable sum to be 1
and the variable element to be 3. the block returns 4, but sum
is not updated with that value

now, inject calls: yield 4,5
(4 is the value that the block returned before)
so the block runs, assigning the variable sum to be 4 and
the variable element to be 5. the block returns 9.

seeing as how there's no more values in the array, inject returns 9
but the block is not called again, so sum is not updated

puts sum
we print the last value of sum, which was 4

···

On Fri, 25 Apr 2008 10:37:43 -0500, Jason Roelofs wrote:

On Fri, Apr 25, 2008 at 11:32 AM, Inbroker Adams <dadravu@yahoo.gr> > wrote:

Hello Rubyists,
I am new to the language and the community. My first problem is this :

i used the following code :

sum = 0
[1,3,5].inject() {|sum, element| sum + element} print sum

I expected to get 9
but instead i get 4

I just installed the Ruby 1.8.6 one-click installer on windows and
wrote the above commands in SciTE. Any suggestions??

You're confused with how variables work in Ruby

puts [1,3,5].inject() {|sum, element| sum + element} # => 9

'sum' in the block is a different scope from your outside 'sum'

--
Ken (Chanoch) Bloom. PhD candidate. Linguistic Cognition Laboratory.
Department of Computer Science. Illinois Institute of Technology.
http://www.iit.edu/~kbloom1/

* 7stud -- <bbxx789_05ss@yahoo.com> (21:41) schrieb:

Don't ever use inject--forget you ever read about it. Use a hand
written loop of your own instead. Your code will be easier to
understand and it will be more efficient.

,----[ /tmp/inject.rb ]

require 'benchmark'

s = {}
range = 1..10_000

Benchmark.bm(8) do | b |
  b.report('inject:') { s[:inject] = range.inject(0) { | sum, n | sum + n } }
  b.report('loop:') do
    sum = 0
    for n in range
      sum += n
    end
    s[:loop] = sum
  end
  b.report('math:') { s[:math] = ((range.max + 1) * range.max) / 2 - ((range.min - 1) * range.min) / 2 }
end

p s

`----

$ ruby1.8 /tmp/inject.rb
              user system total real
inject: 0.130000 0.030000 0.160000 ( 0.155900)
loop: 0.060000 0.010000 0.070000 ( 0.064232)
math: 0.110000 0.010000 0.120000 ( 0.128134)
{:loop=>50005000, :math=>50005000, :inject=>50005000}

$ ruby1.9 /tmp/inject.rb
              user system total real
inject: 0.020000 0.000000 0.020000 ( 0.020228)
loop: 0.060000 0.000000 0.060000 ( 0.063856)
math: 0.000000 0.000000 0.000000 ( 0.000150)
{:loop=>50005000, :math=>50005000, :inject=>50005000}

You are right for Ruby 1.8 (ruby 1.8.5 (2006-08-25) [i486-linux] here),
even math is slower (Bignum I think). But for Ruby 1.9 you are
wrong.

inject is the feature I liked most in Smalltalk.

mfg, simon .... l

Hi --

···

On Sat, 26 Apr 2008, 7stud -- wrote:

Inbroker Adams wrote:

Hello Rubyists,
I am new to the language and the community.
My first problem is this :

i used the following code :

sum = 0
[1,3,5].inject() {|sum, element| sum + element}
print sum

I expected to get 9
but instead i get 4

I just installed the Ruby 1.8.6 one-click installer on windows
and wrote the above commands in SciTE.
Any suggestions??

Don't ever use inject--forget you ever read about it. Use a hand
written loop of your own instead. Your code will be easier to
understand and it will be more efficient.

inject isn't really hard to understand; it's just an iterator with a
kind of feedback loop into the first block parameter. If you find it a
bit tricky I'd still encourage you to study it and accustom yourself
to it. It's awfully useful.

David

--
Rails training from David A. Black and Ruby Power and Light:
   INTRO TO RAILS June 9-12 Berlin
   ADVANCING WITH RAILS June 16-19 Berlin
   INTRO TO RAILS June 24-27 London (Skills Matter)
See http://www.rubypal.com for details and updates!

Thanks so much guys.
So the sum =[1,3,5].inject() {|sum, element| sum + element;}
runs on both 1.8 and 1.9 right???
1.9 Ruby is in beta? (haven't seen it yet)
not on the official site neither on the netbeans 6.1 RC2 that i just
installed

···

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

So let me ask you this:

going back to

sum = [1,3,5].inject(0) {|s,e| s+e}
puts sum

what if you want to return an array that shows each step of the way,
such that:

sum => [1,4,9]

??

···

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

Yes, but if the array is empty rather than 0 you'd get nil. If you don't want that behavior, provide the initial value for the accumulator as an argument:

sum = .inject(0) {|sum, element| sum + element}

gives sum == 0

-Rob

Rob Biedenharn http://agileconsultingllc.com
Rob@AgileConsultingLLC.com

···

On Apr 25, 2008, at 12:20 PM, Inbroker Adams wrote:

Thanks so much guys.
So the sum =[1,3,5].inject() {|sum, element| sum + element;}
runs on both 1.8 and 1.9 right???
1.9 Ruby is in beta? (haven't seen it yet)
not on the official site neither on the netbeans 6.1 RC2 that i just
installed

Thanks so much guys.
So the sum =[1,3,5].inject() {|sum, element| sum + element;} runs on
both 1.8 and 1.9 right???

Yes, but it's best to use a different variable name inside the block.

1.9 Ruby is in beta? (haven't seen it yet) not on the official site
neither on the netbeans 6.1 RC2 that i just installed

Ruby 1.9.0 is a feature-frozen development release of Ruby 1.9, and it
was released on December 25th. I think they're still working on
implementation bugs.

http://www.ruby-lang.org/en/news/2007/12/25/ruby-1-9-0-released/

···

On Fri, 25 Apr 2008 11:20:29 -0500, Inbroker Adams wrote:

--
Ken (Chanoch) Bloom. PhD candidate. Linguistic Cognition Laboratory.
Department of Computer Science. Illinois Institute of Technology.
http://www.iit.edu/~kbloom1/

Jason Lillywhite wrote:

So let me ask you this:

going back to

sum = [1,3,5].inject(0) {|s,e| s+e}
puts sum

what if you want to return an array that shows each step of the way, such that:

sum => [1,4,9]

??

irb(main):003:0> steps =
=>
irb(main):004:0> sum = [1,3,5].inject(0) {|s,e| steps << s+e; steps.last}
=> 9
irb(main):005:0> p steps
[1, 4, 9]

···

--
RMagick: http://rmagick.rubyforge.org/
RMagick 2: http://rmagick.rubyforge.org/rmagick2.html

Here's a way to do it without the extra variable:

[1,3,5].inject() {|s,e| s = s.to_a; s << e + ( s.last || 0)}

or if you still want to inject 0 as the starting value:

[1,3,5].inject(0) {|s,e| s = s.to_a; s << e + s.last}[1..-1]

Now these will give a deprecation warning since Ruby 1.9 does away with
Object#to_a, an alternative is:

[1,3,5].inject(0) {|s,e| s = [s].flatten; s << e + s.last}[1..-1]

···

On Wed, Jun 11, 2008 at 5:50 PM, Tim Hunter <TimHunter@nc.rr.com> wrote:

Jason Lillywhite wrote:

So let me ask you this:

going back to

sum = [1,3,5].inject(0) {|s,e| s+e}
puts sum

what if you want to return an array that shows each step of the way, such
that:

sum => [1,4,9]

??

irb(main):003:0> steps =
=>
irb(main):004:0> sum = [1,3,5].inject(0) {|s,e| steps << s+e; steps.last}
=> 9
irb(main):005:0> p steps
[1, 4, 9]

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

Hi --

···

On Thu, 12 Jun 2008, Rick DeNatale wrote:

On Wed, Jun 11, 2008 at 5:50 PM, Tim Hunter <TimHunter@nc.rr.com> wrote:

Jason Lillywhite wrote:

So let me ask you this:

going back to

sum = [1,3,5].inject(0) {|s,e| s+e}
puts sum

what if you want to return an array that shows each step of the way, such
that:

sum => [1,4,9]

??

irb(main):003:0> steps =
=>
irb(main):004:0> sum = [1,3,5].inject(0) {|s,e| steps << s+e; steps.last}
=> 9
irb(main):005:0> p steps
[1, 4, 9]

Here's a way to do it without the extra variable:

[1,3,5].inject() {|s,e| s = s.to_a; s << e + ( s.last || 0)}

or if you still want to inject 0 as the starting value:

[1,3,5].inject(0) {|s,e| s = s.to_a; s << e + s.last}[1..-1]

Now these will give a deprecation warning since Ruby 1.9 does away with
Object#to_a, an alternative is:

[1,3,5].inject(0) {|s,e| s = [s].flatten; s << e + s.last}[1..-1]

And yet another way:

   [1,3,5].inject([0,]) {|(i,acc),e| [i+e, acc << i+e]}[1]

I suspect each_cons could get involved there somewhere....

David

--
Rails training from David A. Black and Ruby Power and Light:
   INTRO TO RAILS June 9-12 Berlin
   ADVANCING WITH RAILS June 16-19 Berlin
   ADVANCING WITH RAILS July 21-24 Edison, NJ
See http://www.rubypal.com for details and updates!

Rick DeNatale wrote:

[1,3,5].inject() {|s,e| s = s.to_a; s << e + ( s.last || 0)}

If you're okay with 0 being inside the result array you can also do:
[1,3,5].inject([0]) {|s, e| s << s.last + e}

HTH,
Sebastian

···

--
Jabber: sepp2k@jabber.org
ICQ: 205544826

and if you are not

[1,3,5].inject([0]){| a, e| a<< a.last + e}[1..-1]

:wink:
Robert

···

On Thu, Jun 12, 2008 at 9:15 AM, Sebastian Hungerecker <sepp2k@googlemail.com> wrote:

Rick DeNatale wrote:

[1,3,5].inject() {|s,e| s = s.to_a; s << e + ( s.last || 0)}

If you're okay with 0 being inside the result array you can also do:
[1,3,5].inject([0]) {|s, e| s << s.last + e}

Which I had in my original offering before Sebastien trimmed it. <G>

···

On Thu, Jun 12, 2008 at 3:27 AM, Robert Dober <robert.dober@gmail.com> wrote:

On Thu, Jun 12, 2008 at 9:15 AM, Sebastian Hungerecker > <sepp2k@googlemail.com> wrote:
> Rick DeNatale wrote:
>> [1,3,5].inject() {|s,e| s = s.to_a; s << e + ( s.last || 0)}
>
> If you're okay with 0 being inside the result array you can also do:
> [1,3,5].inject([0]) {|s, e| s << s.last + e}

and if you are not

[1,3,5].inject([0]){| a, e| a<< a.last + e}[1..-1]

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

<snip>

[1,3,5].inject([0]){| a, e| a<< a.last + e}[1..-1]

Which I had in my original offering before Sebastien trimmed it. <G>

I only steal from the best of course!!!!
Sorry Rick must have lost it somewhere :frowning:
Cheers
Robert

···

On Thu, Jun 12, 2008 at 1:38 PM, Rick DeNatale <rick.denatale@gmail.com> wrote: