Ruby find in array with offset

2019-08-07 05:53发布

问题:

I'm looking for a way to do the following in Ruby in a cleaner way:

class Array
  def find_index_with_offset(offset, &block)
    [offset..-1].find &block
  end
end

offset = array.find_index {|element| element.meets_some_criterion?}
the_object_I_want = 
    array.find_index_with_offset(offset+1) {|element| element.meets_another_criterion?}

So I'm searching a Ruby array for the index of some object and then I do a follow-up search to find the first object that matches some other criterion and has a higher index in the array. Is there a better way to do this?

What do I mean by cleaner: something that doesn't involve explicitly slicing the array. When you do this a couple of times, calculating the slicing indices gets messy fast. I'd like to keep operating on the original array. It's easier to understand and less error-prone.

NB. In my actual code I haven't monkey-patched Array, but I want to draw attention to the fact that I expect I'm duplicating existing functionality of Array/Enumerable


Edits

  • Fixed location of offset + 1 as per Mladen Jablanović's comment; rewrite error
  • Added explanation of 'cleaner' as per Mladen Jablanović's comment

回答1:

Cleaner is here obviously subjective matter. If you aim for short, I don't think you could do better than that. If you want to be able to chain multiple such finds, or you are bothered by slicing, you can do something like this:

module Enumerable
  def find_multi *procs
    return nil if procs.empty?
    find do |e|
      if procs.first.call(e)
        procs.shift
        next true if procs.empty?
      end
      false
    end
  end
end


a = (1..10).to_a
p a.find_multi(lambda{|e| e % 5 == 0}, lambda{|e| e % 3 == 0}, lambda{|e| e % 4 == 0})
#=> 8

Edit: And if you're not concerned with the performance you could do something like:

array.drop_while{|element|
  !element.meets_some_criterion?
}.drop(1).find{|element|
  element.meets_another_criterion?
}