Создать список файлов на основе массива

Я попробовал кое-что, но на этой неделе у меня возникли ощущения, что у моего мозга каникулы, и мне нужно закончить это дело ... так что я надеюсь, что кто-то может мне помочь.

Мне нужно создать список файлов на основе хэша, который сохраняется в базе данных. Это выглядит так:

['file1', 'dir1/file2', 'dir1/subdir1/file3']

Результат должен быть таким:

  • file1
  • dir1
    • файл2
    • subdir1
      • file3

в html, предпочтительно так (чтобы расширить его с помощью js, чтобы свернуть и выполнить множественный выбор)

<ul>
  <li>file1
  <li>dir1</li>
  <ul>
    <li>file2</li>
    <li>subdir1</li>
    <ul>
      <li>file3</li>
    </ul>
  </ul>
</ul>

Я использую Ruby on Rails и пытаюсь добиться этого в шаблоне RJS. Но это не имеет значения. Вы также можете помочь мне с детальным псевдокодом.

Кто-нибудь знает, как это решить?


Редактировать

Спасибо всем за эти решения. Листинг работает, я расширил его до складного решения для отображения / скрытия содержимого каталога. У меня все еще есть одна проблема: код нацелен на то, чтобы полные пути к файлам были отмечены флажками за записями для синхронизации. Основываясь на решении sris, я могу читать только текущий файл и его подпрограммы, но не весь путь от корня. Для лучшего понимания:

В настоящее время:

[x] dir1
    [x] dir2
        [x] file1

дает мне

флажок с тем же значением, что отображается в тексте, например "файл1" для [x] файл1. Но мне нужен полный путь, например «dir1 / dir2 / file1» для [x] file1.

Есть у кого-нибудь еще подсказка, как это добавить?


person pdu    schedule 17.04.2009    source источник
comment
Вы написали, что это хэш, но вставленный код представляет собой массив, что это такое?   -  person sris    schedule 17.04.2009
comment
Ой, извините, напортачил. Это массив, как я написал. Спасибо, что упомянули Срис.   -  person pdu    schedule 17.04.2009


Ответы (3)


Вот быстрая реализация, которую вы можете использовать для вдохновения. Эта реализация игнорирует порядок файлов во входном массиве.

Я обновил решение, чтобы сохранить весь путь по мере необходимости.

dirs = ['file1', 'dir1/file2', 'dir1/subdir1/file3',  'dir1/subdir1/file5']
tree = {}

dirs.each do |path|
  current  = tree
  path.split("/").inject("") do |sub_path,dir|
    sub_path = File.join(sub_path, dir)
    current[sub_path] ||= {}
    current  = current[sub_path]
    sub_path
  end
end

def print_tree(prefix, node)
  puts "#{prefix}<ul>"
  node.each_pair do |path, subtree| 
    puts "#{prefix}  <li>[#{path[1..-1]}] #{File.basename(path)}</li>"    
    print_tree(prefix + "  ", subtree) unless subtree.empty?
  end
  puts "#{prefix}</ul>"
end

print_tree "", tree

Этот код будет создавать HTML с правильным отступом, как в вашем примере. Но поскольку хэши в Ruby (1.8.6) не упорядочены, порядок файлов не может быть гарантирован.

Полученный результат будет выглядеть так:

<ul>
  <li>[dir1] dir1</li>
  <ul>
    <li>[dir1/subdir1] subdir1</li>
    <ul>
      <li>[dir1/subdir1/file3] file3</li>
      <li>[dir1/subdir1/file5] file5</li>
    </ul>
    <li>[dir1/file2] file2</li>
  </ul>
  <li>[file1] file1</li>
</ul>

Надеюсь, это послужит примером того, как вы можете получить как путь, так и имя файла.

person sris    schedule 17.04.2009
comment
Это почти именно то, что я собирался опубликовать. - person Pesto; 17.04.2009
comment
хорошо, реализовано это решение, но есть еще одна проблема: мне нужны полные пути к файлам как значения флажков (каждый префикс li является флажком). здесь я получаю только файлы. - person pdu; 20.04.2009
comment
Я обновил пример, чтобы удалить повторяющееся использование имени переменной пути. Надеюсь, что это ответ на ваш вопрос - person sris; 20.04.2009

Подумайте о дереве.

  # setup phase
  for each pathname p in list
  do
     add_path_to_tree(p)
  od
  walk tree depth first, emitting HTML

add_path_to_tree рекурсивен

 given pathname p
 parse p into first_element, rest
 # that is, "foo/bar/baz" becomes "foo", "bar/baz"
 add first_element to tree
 add_path_to_tree(rest)

Я оставлю оптимальную структуру данных (список списков) для дерева (список списков) в качестве упражнения.

person Charlie Martin    schedule 17.04.2009

Расширяя ответ sris, если вы действительно хотите, чтобы все было отсортировано и файлы, перечисленные перед каталогами, вы можете использовать что-то вроде этого:

def files_first_traverse(prefix, node = {})
  puts "#{prefix}<ul>" 
  node_list = node.sort
  node_list.each do |base, subtree|
    puts "#{prefix}  <li>#{base}</li>" if subtree.empty?
  end
  node_list.each do |base, subtree|
    next if subtree.empty?
    puts "#{prefix}  <li>#{base}</li>"
    files_first_traverse(prefix + '  ', subtree)
  end
  puts '#{prefix}</ul>'
end
person Pesto    schedule 17.04.2009
comment
Я не хотел слишком загромождать исходный код, но это хорошее дополнение! - person sris; 17.04.2009
comment
Приводить его в порядок необязательно, но спасибо за добавление :-) - person pdu; 17.04.2009