避免在Ruby中多次调用Find.find(“./”)

时间:2010-10-01 12:00:30

标签: ruby block

我不确定这是什么最好的策略。我有一个类,我可以在文件系统中搜索某种模式的文件。我只想执行一次Find.find(“./”)。我该如何处理:

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

3 个答案:

答案 0 :(得分:4)

记住方法调用的(通常是计算密集型)结果,这样你下次调用方法时就不需要重新计算它了,所以你可能会被称为 memoization 想要了解更多相关信息。

实现Ruby的一种方法是使用一个将结果存储在实例变量中的小包装类。 e.g。

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仅在第一次由于短路评估而被调用。在Stackoverflow上有很多other questions解释它。


轻微变化:您可以更改方法以返回所有文件的列表,然后使用Enumerable中的方法,例如grepselect来执行对同一文件列表进行多次搜索。当然,这具有将整个文件列表保存在内存中的缺点。这是一个例子:

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

答案 1 :(得分:1)

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

唯一的问题是,如果目录包含许多文件,那么你在内存中占有一个大数组。

答案 2 :(得分:-2)

system "find / -name #{my_pattern}"

怎么样?