如何将目录名称的哈希构建为键,文件名作为Ruby中的值



我有带有文件的目录,我想构建目录名称作为键和文件名作为值的目录。示例:

/app/foo/create.json
/app/foo/update.json
/app/bar/create.json
/app/bar/update.json

输出:

{
  "foo" => {
    "create.json" => {},
    "update.json" => {}
  },
  "bar" => {
    "create.json" => {},
    "update.json" => {}
  }
}

目前我会这样做:

OUTPUT ||= {}
Dir.glob('app', '**', '*.json')) do |file|
  OUTPUT[File.basename(file)] = File.read(file)
end

但是它没有预期的工作,我不确定如何获取父目录名称。

Dir.glob('*/*.json', base: 'app').each_with_object(Hash.new {|g,k| g[k]={}}) do |fname,h|
  h[File.dirname(fname)].update(File.basename(fname)=>{})
end
  #=> {"foo"=>{"create.json"=>{}, "update.json"=>{}},
  #    "bar"=>{"update.json"=>{}, "create.json"=>{}}}

@Amadan解释了Dir#Glob的使用,这与他的回答完全一样。我已经使用了hash :: new的版本,该版本是执行g[k]时调用块(此处 {|g,k| g[k]={}}(的版本,并且哈希 g没有密钥 k1。另请参阅Hash#update(aka merge!((,file :: dirname and file :: basename。

步骤如下。

a = Dir.glob('*/*.json', base: 'app')
  #=> ["foo/create.json", "foo/update.json", "bar/update.json", "bar/create.json"] 
enum = a.each_with_object(Hash.new {|g,k| g[k]={}})
  #=> #<Enumerator: ["foo/create.json", "foo/update.json", "bar/update.json",
  #                  "bar/create.json"]:each_with_object({})> 

第一个值是由枚举器生成并传递到块的,并且通过数组分解过程分配了块变量:

fname, h = enum.next
  #=> ["foo/create.json", {}] 
fname
  #=> "foo/create.json" 
h #=> {} 
d = File.dirname(fname)
  #=> "foo" 
b = File.basename(fname)
  #=> "create.json" 
h[d].update(b=>{})
  #=> {"create.json"=>{}}

请参阅枚举#下一篇。下一个值是由enum生成的,并传递给块,分配了块变量,并执行块计算。(请注意,构建的哈希(h(已在以下更新。(

fname, h = enum.next
  #=> ["foo/update.json", {"foo"=>{"create.json"=>{}}}] 
fname
  #=> "foo/update.json" 
h #=> {"foo"=>{"create.json"=>{}}} 
d = File.dirname(fname)
  #=> "foo" 
b = File.basename(fname)
  #=> "update.json" 
h[d].update(b=>{})
  #=> {"create.json"=>{}, "update.json"=>{}} 

多两次。

fname, h = enum.next
  #=> ["bar/update.json", {"foo"=>{"create.json"=>{}, "update.json"=>{}}}] 
d = File.dirname(fname)
  #=> "bar" 
b = File.basename(fname)
  #=> "update.json" 
h[d].update(b=>{})
  #=> {"update.json"=>{}} 
fname, h = enum.next
  #=> ["bar/create.json",
  #    {"foo"=>{"create.json"=>{}, "update.json"=>{}}, "bar"=>{"update.json"=>{}}}] 
d = File.dirname(fname)
  #=> "bar" 
b = File.basename(fname)
  #=> "create.json" 
h[d].update(b=>{})
  #=> {"update.json"=>{}, "create.json"=>{}} 
h #=> {"foo"=>{"create.json"=>{}, "update.json"=>{}},
  #    "bar"=>{"update.json"=>{}, "create.json"=>{}}} 

1。这等同于定义哈希如下:g = {}; g.default_proc = proc {|g,k| g[k]={}}。请参阅哈希#default_proc =。

REGEXP的替代方案:

output =
    Dir.glob('*/*.json', base: 'app').
    group_by(&File::method(:dirname)).
    transform_values { |files|
      files.each_with_object({}) { |file, hash|
        hash[File.basename(file)] = File.read(file)
      }
    }

请注意base:File.glob的关键字参数(或Pathname.glob,就此而言(,这简化了我们不需要删除app的内容;另外,出于OP的问题的目的,只需要一个目录级别,因此*代替**

最新更新