Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

find first element in array for which block returns true and return the block's return value

Tags:

ruby

I need to iterate over an array and apply a supplied block to each element, and return the first true value returned by the block, which implies that I need to stop immediately as soon as I get a true value.

below is my code. I am a ruby newbie, and I am not sure if this code is reinventing the wheel. Maybe there is a library method or methods that can do that already? or may be this code can be simplified?

RS = {
  :x => %w(\d+ a\d+ bb\d+ ccc\d+).map{|x| /^#{x}$/},
  :y => %w(\w+ 1\w+ 22\w+ 333\w+).map{|x| /^#{x}$/}
}.freeze

def find s, t
  r = RS[s]
  if r
    r.each do |p|
      m = p.match t
      return m if m
    end
    nil
  end
end

p find :x, 'bb12345'
like image 672
akonsu Avatar asked Mar 14 '13 20:03

akonsu


People also ask

Can you return a block in Ruby?

You cannot do that in Ruby. The return keyword always returns from the method or lambda in the current context. In blocks, it will return from the method in which the closure was defined. It cannot be made to return from the calling method or lambda.

What does .first mean in Ruby?

The first() is an inbuilt method in Ruby returns an array of first X elements. If X is not mentioned, it returns the first element only. Syntax: range1.first(X) Parameters: The function accepts X which is the number of elements from the beginning. Return Value: It returns an array of first X elements.

What is return in Ruby?

Ruby methods ALWAYS return the evaluated result of the last line of the expression unless an explicit return comes before it. If you wanted to explicitly return a value you can use the return keyword.


2 Answers

If you want the result of the block you could do it this way. This will iterate over the whole array, but wont evaluate any matches after the first one.

def find(s,t)
  RS[s].inject(nil) {|m, p| m || p.match(t)}
end

You can break out early doing something like this

RS[s].inject(nil) {|m, p| (m && (break m)) || p.match(t)}
like image 110
Alex.Bullard Avatar answered Oct 03 '22 11:10

Alex.Bullard


This is duplicated with: Ruby - Array.find, but return the value the block

You want a lazy map:

[nil, 1, 2, 3].lazy.map{|i| i && i.to_s}.find{|i| i}    
# => "1"
like image 34
ribamar Avatar answered Oct 03 '22 09:10

ribamar