8
a, b, c = 0, 1, 2
[a, b, c].find(&:zero?) # => 0

Is there any method that finds the first element for which the block returns false?

[a, b, c].the_method(&:zero?) # => 1

In other words, it would behave the same way as:

[a, b, c].reject(&:zero?).first
Pablo B.
  • 1,823
  • 1
  • 17
  • 27

3 Answers3

11

There is not, but you could create one either the clean-ish way:

a = [0,2,1,0,3]

module Enumerable
  def first_not(&block)
    find{ |x| !block[x] }
  end
end

p a.first_not(&:zero?)
#=> 2

...or the horribly-amusing hack way:

class Proc
  def !
    proc{ |o,*a| !self[o,*a] }
  end
end

p a.find(&!(:zero?.to_proc))
#=> 2

...or the terse-but-terribly-dangerous way:

class Symbol
  def !
    proc{ |o,*a| !o.send(self,*a) }
  end
end

p a.find(&!:zero?)
#=> 2

But I'd advocate just skipping the tricky Symbol#to_proc usage and saying what you want:

p a.find{ |i| !i.zero? }
#=> 2
Phrogz
  • 296,393
  • 112
  • 651
  • 745
3

If you're using Ruby 2.0, you may be able to do lazy.reject(&:zero?).first without the performance penalty of going through the full array.

Andrew Grimm
  • 78,473
  • 57
  • 200
  • 338
2

As far as I can tell there is not a standard method to do this (given that find_all and reject reference each other, but find does not reference anything). If you need it frequently (especially if the reject is too slow) you can write your own

module Enumerable

  def first_reject(&block)
    find {|a| not (block.call(a)) }
  end

end
Kathy Van Stone
  • 25,531
  • 3
  • 32
  • 40