在数组中找到第一个元素,该块返回true并返回该块的返回值

时间:2022-06-29 21:19:18

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'

4 个解决方案

#1


1  

Hopefully still actual: here a solution using detect, i made it possible to verbose the output so you can see which expressions are evaluated before returning a hit.

希望仍然是实际的:这里有一个使用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


2  

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)}

#3


1  

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

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

You want a lazy map:

你想要一个懒惰的地图:

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

#4


0  

If your regex patterns are simple, you can just apply the regex again at the end, maybe.

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

Something like:

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

Although it makes one redundant call to match, it is easier to understand.

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

First, find the pattern you want, then use that pattern.

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

#1


1  

Hopefully still actual: here a solution using detect, i made it possible to verbose the output so you can see which expressions are evaluated before returning a hit.

希望仍然是实际的:这里有一个使用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


2  

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)}

#3


1  

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

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

You want a lazy map:

你想要一个懒惰的地图:

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

#4


0  

If your regex patterns are simple, you can just apply the regex again at the end, maybe.

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

Something like:

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

Although it makes one redundant call to match, it is easier to understand.

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

First, find the pattern you want, then use that pattern.

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