【问题标题】:Avoiding making multiple calls to Find.find("./") in Ruby避免在 Ruby 中多次调用 Find.find("./")
【发布时间】:2010-10-01 12:00:29
【问题描述】:

我不确定什么是最好的策略。我有一门课,我可以在文件系统中搜索特定模式的文件。我只想执行一次 Find.find("./") 。我将如何处理:

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

【问题讨论】:

  • 你能澄清一下这个问题吗? 只执行一次 Find.find("./") 是什么意思
  • 我认为提问者的意思是缓存Find.find('./')的结果。
  • @Swanand 啊,谢谢!在此基础上,我会尝试回答。

标签: ruby block


【解决方案1】:

记住方法调用的(通常是计算密集型的)结果,以便下次调用该方法时不需要重新计算它被称为 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 由于短路评估而只会在第一次被调用。 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

【讨论】:

  • 没关系,但是如果我现在想先找到 .xml,然后是 .cpp、.c、.h,并且我在文件系统的大部分区域上执行此操作,我最终会调用 Find .find("./") 多次。还是?
  • hm.. 我想我需要将文件系统的所有条目存储在一个文本文件中,并将 Finder 类应用于文本文件,这应该比 find() 每次都快,当然,我必须在我进行过滤之前更新文本文件。
  • @poseid 我在答案的末尾添加了一个变体。看看这是否有用。
【解决方案2】:

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

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

【讨论】:

  • 谢谢。我基本上错过了将块转换回方法的要点。
【解决方案3】:

system "find / -name #{my_pattern}"怎么样

【讨论】:

  • 如果您想要结果,请使用反引号,而不是直接输出到标准输出。
  • 这肯定会在 Windows 中失败,在任何其他可能找不到可用或采用相同参数的平台中。我只会将此作为最后的措施。
  • 我实际上在发布后立即删除了这个答案(但显然它没有被删除),因为它的问题比我第二次阅读问题后提到的要多。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-31
  • 2019-10-31
相关资源
最近更新 更多