Enumerable#find_yield, useful shortcut? better name?

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

  end

Thanks.

I would call the method "unnecessary". Especially since we already have
a built in syntax which is more concise:

  [1,2,3].find { |_| false } # => nil
  [1,2,3].find { |_| false } || 1 # => 1

···

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?

--
Aaron Patterson
http://tenderlovemaking.com/

#where doesn't read too badly

martin

···

On Thu, Nov 12, 2009 at 9:37 PM, Intransition <transfire@gmail.com> 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?

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

a

=> [1, 2, 3, 99]

···

--
Posted via http://www.ruby-forum.com/\.

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.

Kind regards

  robert

···

On 12.11.2009 17:41, Aaron Patterson wrote:

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 } # => nil
  [1,2,3].find { |_| false } || 1 # => 1

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

As Aaron,
I prefer the simple built-in method, with what u want to do with the object
after:

obj1.foo? #=> false
obj2.foo? #=> true
obj2.foo #=> "value"

[obj1, obj2].find_yield { |obj| obj.foo if obj.foo? } #=> "value"

[obj1, obj2].find { |obj| obj.foo? }.foo #=> "value"

Even more concise ...
The only problem I see is if we don't find, we'll call foo on nothing(nil).

So to have the same behavior:
x = [obj1, obj2].find(nil) { |obj| obj.foo? }
x.foo unless foo.nil? #=> "value"

And I think it's quite normal we have to manage with a structure(the if) how
to manage when we didn't find.

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?

If you want to take several objects, you would use [obj1, obj2].select {

obj> obj.foo? }.map {|e| e.foo}

So the idea of Robert Klemme is accurate, sure.

···

2009/11/13 Martin DeMello <martindemello@gmail.com>

On Thu, Nov 12, 2009 at 9:37 PM, Intransition <transfire@gmail.com> 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

martin

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.

···

On Nov 13, 5:13 am, Martin DeMello <martindeme...@gmail.com> wrote:

On Thu, Nov 12, 2009 at 9:37 PM, Intransition <transf...@gmail.com> 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

You have misunderstood. The desire is to do something when a match is
found, not if there is no match.

···

On Nov 16, 4:41 am, Brian Candler <b.cand...@pobox.com> wrote:

Unless I have misunderstood, I think there is an almost identical
facility built-in:

>> [1,2,3].find(lambda {-1}) { |x| x > 10 }

=> -1

--
-yossef

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.

···

On Nov 13, 9:12 am, Benoit Daloze <erego...@gmail.com> wrote:

As Aaron,
I prefer the simple built-in method, with what u want to do with the object
after:

obj1.foo? #=> false
obj2.foo? #=> true
obj2.foo #=> "value"

[obj1, obj2].find_yield { |obj| obj.foo if obj.foo? } #=> "value"

[obj1, obj2].find { |obj| obj.foo? }.foo #=> "value"

Even more concise ...
The only problem I see is if we don't find, we'll call foo on nothing(nil).

So to have the same behavior:
x = [obj1, obj2].find(nil) { |obj| obj.foo? }
x.foo unless foo.nil? #=> "value"

And I think it's quite normal we have to manage with a structure(the if) how
to manage when we didn't find.

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?