Assume I have in Ruby an Enumerable coll
, and the following code (which of course does not produce the desired result):
# WRONG approach
def f(coll)
pivot = coll.find do
|element|
t = element.calculate
t > 0
end
pivot && t # Return the calculated value
end
This does not work, since each block has its own scope for locals, and the t of the inner block is different from the t of the outer block. What is the most elegant way to fix it? I can think of the following possibilities:
def f(coll)
pivot = coll.find do
|element|
element.calculate > 0
end
pivot && pivot.calculate
end
Drawback: The last calculation is unnecessarily done twice.
def f(coll)
pivot = coll.find do
|element|
@t = element.calculate
@t > 0
end
pivot && @t
end
Drawback: It's ugly design.
find
on the calculated values: def f(coll)
coll.map(&:calculate).find {|x| x>0}
end
Drawback: Unnecessary calculations
Is there any better way to do it, perhaps using binding
to make the local variable accessible inside the block? If so, how can it be done?
The simplest way to have available a value outside a block is to use a local variable declared (by initialising) outside the block:
t = nil
call.find do |element|
t = element.calculate
t > 0
end
# here t is available
There is a more complex but may be more idiomatic/functional way suited for your case - to calculate t
lazily and using lazy #zip
find a pair of element
and t
:
ts = col.lazy.map { |e| e.calculate }
element, t = enum.lazy.zip(ts).find { |e, t| t < 0 }