I've want to write code that does this (well, a much more complex version of this, anyway):
answer = nil
array.each do |e|
x = complex_stuff_with(e)
if x.is_the_one_i_want?
answer = x
break
end
end
This is obviously not satisfactory. Iterating through an array like this is a code smell.
Ideally, I want some method on Array that will let me test each element in turn, and return my answer and stop when I have one. Is there such a method?
The closest I've been able to come to it is by using break
inside #inject
. But I'm still basically doing the iteration by hand!
answer = array.inject do |_,e|
x = complex_stuff_with(e)
break x if x.is_the_one_i_want?
end
Update: It would appear that the reason I can't find such a method is because no such method exists.
Update: Spoke too soon! I need the Lazy Operator! Thanks, everyone.
What you are effectively doing is, first map
ping the elements of the Array
with a transformation, and then find
ing the first transformed element that satisfies some predicate.
We can express this like this (I'm re-using the definitions from @iGian's answer, but with an added side-effect so that you can observe the evaluation of the transformation operation):
def complex_stuff_with(e)
p "#{__callee__}(#{e.inspect})"
e**2
end
ary = [1, 2, 3, 2]
x_i_want = 4
ary
.map(&method(:complex_stuff_with))
.find(&x_i_want.method(:==))
# "complex_stuff_with(1)"
# "complex_stuff_with(2)"
# "complex_stuff_with(3)"
# "complex_stuff_with(2)"
#=> 4
This gives us the correct result but not the correct side-effects. You want the operation to be lazy
. Well, that's easy, we just need to convert the Array
to a lazy enumerator first:
ary
.lazy
.map(&method(:complex_stuff_with))
.find(&x_i_want.method(:==))
# "complex_stuff_with(1)"
# "complex_stuff_with(2)"
#=> 4
Or, using the definitions from your question:
array
.lazy
.map(&method(:complex_stuff_with))
.find(&:is_the_one_i_want?)