7

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

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

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

4 回答 4

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)}
于 2013-03-14T20:48:53.333 回答
2

这与以下内容重复:Ruby - Array.find,但返回块的值

你想要一张懒惰的地图:

[nil, 1, 2, 3].lazy.map{|i| i && i.to_s}.find{|i| i}    
# => "1"
于 2017-10-17T12:07:42.100 回答
1

希望仍然是实际的:这里有一个使用检测的解决方案,我可以详细说明输出,以便您可以查看在返回命中之前评估了哪些表达式。

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">
于 2014-03-23T16:49:22.953 回答
0

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

就像是:

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

尽管它进行了一次冗余调用来匹配,但它更容易理解。

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

于 2013-03-15T05:58:36.603 回答