Why is my var undefined?

T

Tim

I'm new to ruby and I have the following code:

index=0
unsorted_array.each do |value|
if index==0
smallest=value
smallest_index=0
elsif value<smallest
smallest=value
smallest_index=index
end
index=index+1
end

When it gets to index 1, it crashes and says that smallest is
undefined (on the elsif line). Why is that, when it gets defined in
the first pass (index = 0) ?

Thanks for helping a newbie out.

Tim
 
I

Ilan Berci

Tim said:
I'm new to ruby and I have the following code:

index=0
unsorted_array.each do |value|
if index==0
smallest=value
smallest_index=0
elsif value<smallest
smallest=value
smallest_index=index
end
index=index+1
end

When it gets to index 1, it crashes and says that smallest is
undefined (on the elsif line). Why is that, when it gets defined in
the first pass (index = 0) ?

Thanks for helping a newbie out.

Tim

It's only defined for the scope that it's in.. which is the "if" block..
Once it leaves that block and your code returns to the
"unsorted_array.each" scope, "smallest" is out of scope and therefore no
longer defined.

Dave Thomas has a free online version of Ruby 1.6 referred as the Pick
Axe book which discusses scope and I think you will find it very useful

hth

ilan
 
T

Todd Benson

I'm new to ruby and I have the following code:

index=0

you could insert "smallest = nil" here
unsorted_array.each do |value|
if index==0
smallest=value
smallest_index=0
elsif value<smallest
smallest=value
smallest_index=index
end
index=index+1
end

When it gets to index 1, it crashes and says that smallest is
undefined (on the elsif line). Why is that, when it gets defined in
the first pass (index = 0) ?

Not sure what you are trying to do, but if your data is not unique...

a = 5,1,4,7,2,1,9,2,1
smallest = a.min
s_indexes = []
a.each_with_index {|v, i| s_indexes << i if v == a.min}

If you don't want to do it that way, then...

a = 5,1,4,7,2,1,9,2,1
smallest, s_indexes = a.first, []
a.inject(a.first) {|m, e| e < m ? e : m}
a.each_with_index {|v, i| s_indexes << i if v == a.min}

Todd
 
T

Todd Benson

a.inject(a.first) {|m, e| e < m ? e : m}
a.each_with_index {|v, i| s_indexes << i if v == a.min}


Sorry, these lines are supposed to be...

smallest = a.inject(a.first) {|m, e| e < m ? e : m}
a.each_with_index {|v, i| s_indexes << i if v <= smallest}

Todd
 
I

Isidor Isa

Todd said:
Sorry, these lines are supposed to be...

smallest = a.inject(a.first) {|m, e| e < m ? e : m}
a.each_with_index {|v, i| s_indexes << i if v <= smallest}

Todd

In Ruby 1.9, finding indexes of all elements which have minimal value
is easily done using a new iterator chaining feature:



a = 5, 1, 4, 7, 2, 1, 9, 2, 1

min_value = a.min



a.each_with_index.inject([]){|accum, (elem, index)|

elem == min_value ? accum << index : accum

}

Output:

=> [1, 5, 8]


Best regards
Isidor Nikolic
 
E

Eivind Eklund

I'm new to ruby and I have the following code:

Add
smallest = nil
smallest_index = 0
here, and your code will work.

index=0
unsorted_array.each do |value|
if index==0
smallest=value
smallest_index=0
elsif value<smallest
smallest=value
smallest_index=index
end
index=index+1
end

When it gets to index 1, it crashes and says that smallest is
undefined (on the elsif line). Why is that, when it gets defined in
the first pass (index = 0) ?

The variable is not "pass"-based - it is "scope" based, ie, it only
exists inside a particular *lexical* - that is, textual - part of your
program (in this case, your if statement, NOT the loop). In other
words, you get a new variable for each pass through the loop.

By adding the initialization, you get th same variable all loop iterations.

Here is another variant of your code that uses essensially the same
algorithm and simplifies the code a bit:

smallest_index = 0
smallest_value = nil
unsorted_array.each_with_index do |value, index|
if !smallest_value || value<smallest
smallest=value
smallest_index=index
end
end


Eivind.
 
S

Sebastian Hungerecker

Ilan said:
It's only defined for the scope that it's in.. which is the "if" block

It's not local to the if-block. It's local to each execution of the each-
block.

HTH,
Sebastian
 
E

Eivind Eklund

The variable is not "pass"-based - it is "scope" based, ie, it only
exists inside a particular *lexical* - that is, textual - part of your
program (in this case, your if statement, NOT the loop).

This was slightly clumsily written; the variable leak through to the
end of the block, but isn't present for the entire loop. Sebastians
description is correct.

Eivind.
 
T

Tim

Thanks to all for the help. I take it from the comments here that any
variables which are defined in an iteration block (or a Proc)are local
to each iteration. Thinking about it, that makes sense because each
iteration requires its own call from each (or each_with_index,
etc.)...with the variables being treated somewhat like method
variables.
 

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

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top