Why is my var undefined?

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

Tim wrote:

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

On Feb 2, 2008 6:09 PM, Tim [email protected] wrote:

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

index=0

you could insert “smallest = nil” here

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

Todd B. wrote:

On Feb 2, 2008 11:05 PM, Todd B. [email protected] wrote:

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

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

On Feb 2, 2008 11:05 PM, Todd B. [email protected] wrote:

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

Ilan B. wrote:

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

On Feb 3, 2008 11:50 AM, Eivind E. [email protected] wrote:

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.

On Feb 3, 2008 1:09 AM, Tim [email protected] wrote:

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

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

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.

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.