[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Array inject function problem

Inbroker Adams

4/25/2008 3:32:00 PM

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

18 Answers

Jason Roelofs

4/25/2008 3:38:00 PM

0

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

Rob Biedenharn

4/25/2008 3:50:00 PM

0

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


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://agileconsult...
Rob@AgileConsultingLLC.com



Stefano Crocco

4/25/2008 3:53:00 PM

0

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

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

Ken Bloom

4/25/2008 4:08:00 PM

0

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'

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

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

Inbroker Adams

4/25/2008 4:20:00 PM

0

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

Rob Biedenharn

4/25/2008 4:47:00 PM

0

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


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://agileconsult...
Rob@AgileConsultingLLC.com



Ken Bloom

4/25/2008 5:00:00 PM

0

On Fri, 25 Apr 2008 11:20:29 -0500, 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???

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

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

7stud --

4/25/2008 7:42:00 PM

0

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

Simon Krahnke

4/25/2008 10:18:00 PM

0

* 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

David A. Black

4/25/2008 11:03:00 PM

0

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.r... for details and updates!