This method has long been suggested to me as #map_detect. At first I
wasn’t sure of it’s usefulness. But now I think it’s okay. (Your
thoughts?). In any case, the name has to go. Currently I’m thinking #find_yield. Any better suggestions?
module Enumerable
# Similar to #detect and #find. Yields each element to the block
# and returns the first result that evaluates as *true*,
# terminating early.
#
# obj1.foo? #=> false
# obj2.foo? #=> true
# obj2.foo #=> "value"
#
# [obj1, obj2].find_yield { |obj| obj.foo if obj.foo? } #=>
“value”
#
# If the block is never true, return the +fallback+ parameter,
# or nil if no +fallback+ is specified.
#
# [1,2,3].find_yield { || false } #=> nil
# [false].find_yield(1) { || false } #=> 1
#
def find_yield(fallback = nil) #:yield:
each do |member|
result = yield(member)
return result if result
end
fallback
end
On Fri, Nov 13, 2009 at 01:07:41AM +0900, Intransition wrote:
This method has long been suggested to me as #map_detect. At first I
wasn’t sure of it’s usefulness. But now I think it’s okay. (Your
thoughts?). In any case, the name has to go. Currently I’m thinking #find_yield. Any better suggestions?
I would call the method “unnecessary”. Especially since we already have
a built in syntax which is more concise:
[1,2,3].find { |_| false } || 1 # => 1
I disagree. The difference between TMISFAN (the method in search for a
name) and your solution is that TMISFAN returns the result of the block
evaluation and not the element contained in the collection.
I don’t have frequent use for this but it occurred just a few days ago.
This is what I did then - roughly:
x = nil
enum.any? {|e| e > 10 and x = e * 2}
This is dummy code of course, I don’t have the concrete example handy.
The main point is that #any? will short circuit (like #find) and the
special value is reserved via the variable.
How about #find_map? This expresses what happens, first a search and
then a mapping of the value - sort of.
On Thu, Nov 12, 2009 at 9:37 PM, Intransition [email protected]
wrote:
This method has long been suggested to me as #map_detect. At first I
wasn’t sure of it’s usefulness. But now I think it’s okay. (Your
thoughts?). In any case, the name has to go. Currently I’m thinking #find_yield. Any better suggestions?
On Thu, Nov 12, 2009 at 9:37 PM, Intransition [email protected] wrote:
This method has long been suggested to me as #map_detect. At first I
wasn’t sure of it’s usefulness. But now I think it’s okay. (Your
thoughts?). In any case, the name has to go. Currently I’m thinking #find_yield. Any better suggestions?
#where doesn’t read too badly
I agree. But to me #where also conveys the same meaning as #select.
Plus I tend to like it’s use in higher-order messaging, and I have no
desire to tread on those toes. However, you did get me thinking in a
different direction which ultimately led me to #found, which conveys
it’s relation to #find and that we want, not the element itself, but
what was “found”. Though I admit, it has a strange tense for a method
name.
Unless I have misunderstood, I think there is an almost identical
facility built-in:
[1,2,3].find(lambda {-1}) { |x| x > 10 }
=> -1
It’s slightly inconvenient to require a proc for the default, but it
means you can create an ‘expensive’ object or modify the collection with
a side-effect:
a = [1,2,3]
=> [1, 2, 3]
a.find(lambda{ a << 99; a.last }) { |x| x > 10 }
=> 99
But I’m probably missing a special case. Could you give a example in
situation, to see if it is easier to read or not?
I think you make a good point. The difference lies in where you are
able to put the logic. Eg.
x = [obj1, obj2].find{ |obj| obj.foo? }
y = x ? do_something_with(x.foo) : nil
vs.
y = [obj1, obj2].find_yield do |obj|
do_something_with(obj.foo) if obj.foo?
end
These are functionally equivalent, so really this is just a matter
constructional preference. If there were a way to make the former more
concise, then the case for the later would probably be moot, but I’m
not sure there is.
This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.