在数组中查找哪个块返回true并返回块的返回值

时间:2013-03-14 20:42:58

标签: ruby

我需要迭代一个数组并将一个提供的块应用于每个元素,并返回该块返回的第一个真值,这意味着我需要在获得真值后立即停止。

下面是我的代码。我是一个红宝石新手,我不确定这个代码是否重新发明轮子。也许有一种库方法或方法可以做到这一点?或者可以简化这段代码?

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'

4 个答案:

答案 0 :(得分:2)

如果你想要块的结果,你可以这样做。这将迭代整个数组,但不会在第一个之后评估任何匹配。

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

你可以早点做出像这样的事情

RS[s].inject(nil) {|m, p| (m && (break m)) || p.match(t)}

答案 1 :(得分:1)

希望仍然是实际的:这里有一个使用detect的解决方案,我可以对输出进行详细说明,这样你就可以在返回命中之前看到哪些表达式得到了评估。

def find_match symbol, string , verbose = false, match = nil
  if verbose
    RS.detect{|x,v|x==symbol;v.detect{|re|puts re;match=string.match(/#{re}/)}}
  else
    RS.detect{|x,v|x==symbol;v.detect{|re|match=string.match(/#{re}/)}}
  end
  match
end

p find_match :x, 'bb12345'
p find_match :x, 'ee12345' , true #verbose output
p find_match :x, '12345'
p find_match :y, '22abcd'

#<MatchData "bb12345">
(?-mix:^\d+$)
(?-mix:^a\d+$)
(?-mix:^bb\d+$)
(?-mix:^ccc\d+$)
(?-mix:^\w+$)
#<MatchData "ee12345">
#<MatchData "12345">
#<MatchData "22abcd">

答案 2 :(得分:1)

这与以下内容重复:Ruby - Array.find, but return the value the block

你想要一张懒惰的地图:

[nil, 1, 2, 3].lazy.map{|i| i && i.to_s}.find{|i| i}    
# => "1"

答案 3 :(得分:0)

如果您的正则表达式模式很简单,可以在最后再次应用正则表达式。也可以。

类似的东西:

def find(s,t)
  r = RS[s] and r.find{|p| p.match(t)}.try(:match, t)
end

虽然它使一个冗余调用匹配,但更容易理解。

首先,找到您想要的模式,然后使用该模式。