2010-10-01 50 views
1

我不确定最佳策略是什么。我有一个课程,我可以在文件系统中搜索特定模式的文件。我只想执行一次Find.find(“./”)。我将如何处理这:避免在Ruby中对Find.find(“./”)进行多次调用

def files_pattern(pattern) 
    Find.find("./") do |f| 
     if f.include? pattern 
      @fs << f 
     end 
    end 
    end 
+0

你能否澄清一下这个问题。你是什​​么意思*只执行Find.find(“./”)一次*? – mikej 2010-10-01 12:32:58

+0

我认为提问者意味着缓存Find.find('./')的结果。 – Swanand 2010-10-01 12:46:04

+0

@Swanand啊,谢谢!在这个基础上我会有一个答案。 – mikej 2010-10-01 13:00:04

回答

4

记住一个方法调用(通常是计算密集型)的结果,这样你就不需要它在下一次重新计算是已知的作为memoization所以你可能会想要阅读更多关于这一点。

实现它的一种方式是,Ruby将使用将结果存储在实例变量中的小封装类。例如

class Finder 
    def initialize(pattern) 
    @pattern = pattern 
    end 

    def matches 
    @matches ||= find_matches 
    end 

    private 

    def find_matches 
    fs = [] 
    Find.find("./") do |f| 
     if f.include? @pattern 
     fs << f 
     end 
    end 
    fs 
    end 
end 

然后你就可以这样做:

irb(main):089:0> f = Finder.new 'xml' 
=> #<Finder:0x2cfc568 @pattern="xml"> 
irb(main):090:0> f.matches 
find_matches 
=> ["./example.xml"] 
irb(main):091:0> f.matches # won't result in call to find_matches 
=> ["./example.xml"] 

注:||=操作执行只有在左侧的变量不计算为False分配。即@matches ||= find_matches@matches = @matches || find_matches的简写,其中find_matches将仅由于短路评估而被首次调用。有很多other questions在Stackoverflow上解释它。


轻微的变化:你可以改变你的方法来返回所有文件列表,然后使用从Enumerablegrepselect方法来对文件的同一列表进行多次搜寻。当然,这存在将整个文件列表保存在内存中的缺点。这里虽然是一个例子:

def find_all 
    fs = [] 
    Find.find("./") do |f| 
    fs << f 
    end 
    fs 
end 

,然后用它喜欢:

files = find_all 
files.grep /\.xml/ 
files.select { |f| f.include? '.cpp' } 
# etc 
+0

这是可以的,但如果我现在想要找到第一个.xml,然后.cpp,.c,.h,并且我在文件系统的大部分上执行此操作,我最终调用Find.find(“./” ) 多次。要么? – poseid 2010-10-01 13:34:56

+0

hm ..我想我需要将文件系统的所有条目存储在文本文件中,并将Finder类应用于文本文件,每次都应该比find()更快,因为我必须在过滤之前更新文本文件。 – poseid 2010-10-01 13:48:50

+0

@poseid我在答案的末尾添加了一个变体。看看这是否有用。 – mikej 2010-10-01 13:54:02

-2

调用的方法怎么样system "find/-name #{my_pattern}"

+1

如果您想要结果而不是仅仅输出标准输出,请使用返回标记。 – 2010-10-01 12:17:22

+0

这在Windows中肯定会失败,并且在任何其他可能没有找到可用或采用相同参数的平台中都会失败。我只会作为最后一项措施来做到这一点。 – Pablo 2010-10-01 12:34:23

+0

我实际上在发布后立即删除了这个答案(但显然它并没有被删除),但是在我第二次阅读这个问题之后,还有更多的问题。 – 2010-10-01 14:33:25

1

如果我正确理解你的问题你要运行到Find.find结果分配给一个实例变量。您可以将现在的块移至单独的方法,并调用该方法仅返回与您的模式匹配的文件。

唯一的问题是,如果目录包含很多文件,你在内存中保存一个大数组。

+0

谢谢。我基本上错过了将块转换回方法的观点。 – poseid 2010-10-01 14:11:24