Как создать хэш имен каталогов в качестве ключей и имен файлов в качестве значений в Ruby? - PullRequest
1 голос
/ 13 мая 2019

У меня есть каталоги с файлами, и я хотел бы создать хэш имен каталогов в качестве ключей и имен файлов в качестве значений. Пример:

/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

Но он не работает должным образом, я не уверен, как получить имя родительского каталога.

Ответы [ 2 ]

1 голос
/ 13 мая 2019
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"=>{}}}

@ Амадан объясняет использование Dir # glob , что в точности соответствует его ответу.Я использовал версию Hash :: new , которая вызывает блок (здесь {|g,k| g[k]={}}), когда выполняется g[k] и хеш g не имеет ключа k. 1. См. Также Hash # update (он же merge!), File :: dirname и 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]={}}.См. Hash # default_proc = .

1 голос
/ 13 мая 2019

Альтернатива регулярному выражению:

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 требуется только один уровень каталога, поэтому * вместо **.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...