2011-03-07 58 views
0
def get_type 
    x = [{:type=>'A', :patterns=>['foo.*']}, {:type=>'B', :patterns=>['bar.*']}] 

    name = 'foo.txt' 

    result = x.each { |item| 
    item[:patterns].each { |regex| 
     puts "Checking #{regex} against #{name}" 
     if !name.match(regex).nil? 
     puts "Found match: #{item[:type]}" 
     return item[:type] 
     end 
    } 
    } 
end 

result = get_type 
puts "result: #{result}" 

预期输出:从一个嵌套的每个块返回一个值,试图用“回归”

Checking foo.* against foo.txt 
Found match: A 
result: A 

然而,所有我看到的是:

Checking foo.* against foo.txt 
Found match: A 

我目前的解决办法是这样的:

def get_type 
    x = [{:type=>'A', :patterns=>['foo.*']}, {:type=>'B', :patterns=>['bar.*']}] 

    name = 'foo.txt' 

    result = [] 
    x.each { |item| 
    item[:patterns].each { |regex| 
     puts "Checking #{regex} against #{name}" 
     if !name.match(regex).nil? 
     puts "Found match: #{item[:type]}" 
     result << item[:type] 
     end 
    } 
    } 
    result[0] unless result.empty? 
end 

为什么第一个ap打工?或者可能是'工作',我只是不明白为什么我没有得到我所期望的。

回答

1

适合我。你真的用它调用它吗?

result = get_type puts "result: #{result}" 

?因为这根本不应该工作,尽管我假设有一个换行符在你发布时会被吃掉。

+0

你说得对。我还有其他一些错字。我发现的是,如果没有匹配,那么“结果”将被设置为等于'x'数组。这是我需要注意的一个条件。 – codecraig 2011-03-07 16:14:39

2

我可以提出重构吗?您的代码看起来有点笨重,因为当您实际上需要map + first(功能)时,您正在使用each循环(必要)。随着Ruby可枚举不偷懒,这将是低效的,所以人们通常建立在抽象Enumerable#map_detect(或find_yield,或find_first,或map_first):

def get_type_using_map_detect(name) 
    xs = [{:type => 'A', :patterns => ['foo.*']}, {:type => 'B', :patterns => ['bar.*']}] 
    xs.map_detect do |item| 
    item[:patterns].map_detect do |regex| 
     item[:type] if name.match(regex) 
    end 
    end 
end 

这是一个可能的实施方法:

module Enumerable 
    # Like Enumerable#map but return only the first non-nil value 
    def map_detect 
    self.each do |item| 
     if result = (yield item) 
     return result 
     end 
    end 
    nil 
    end 
end