2014-09-05 52 views
1

的陣列我有一個數組排序的文件列表,如:從文件列表,動態創建哈希爲dynatree

arr = ["./a.txt", "./b.txt", "./bar/z.php", "./foo/hello/y.php", "./foo/x.php"] 

如何創建一個dynatree對象出來呢? 爲它dynatree對象,應該是這樣的:

[{"name"=>".", "title" => ".", "isDir" => true, "children" => 
    [{"name"=>"a.txt", "title" => "a.txt"}, 
    {"name"=>"b.txt", "title" => "b.txt"}, 
    {"name" => "bar", "title"=>"bar", "isDir"=>true, "children" => 
     [{"name" => "z.php", "title" => "z.php"}, 
     {"name" => "foo", "title" => "foo", "isDir" => true, "children" => 
      [{"name" => "x.php", "title" => "x.php"}, 
      { "name" => "hello", "title" => "hello", "children" => 
       [{"name" => "y.php", "title"=>"y.php"} 
       ] 
      } 
      ] 
     } 
     ] 
    } 
    ] 
}] 

PS:這個問題似乎是一個懶惰的職位,但我已經花了20個多小時,現在解決這個。所以任何幫助將不勝感激。謝謝。

+1

您的需求總是...... *難* * :-) – 2014-09-05 09:08:37

回答

1

我的想法是遍歷每個路徑。每條路徑由/分成幾部分。最後一部分是文件,其他部分是目錄。

我會通過添加新目錄的每個部分,除非它們已被添加。在每次迭代結束時,我將上下文切換到下一個級別 - 最後一個目錄的children數組。

文件是最後一部分 - 我簡單地將它附加到當前上下文中。

arr = ["./a.txt", "./b.txt", "./bar/z.php", "./foo/hello/y.php", "./foo/x.php"] 

tree = [] 

arr.each do |path| 
    # start at the beginning on each iteration 
    current_level = tree 

    # split path by '/' 
    splitted_path = path.split('/') 

    # remember the size of parts in path to distinct files from folders 
    size = splitted_path.size 

    # iterate over each part of a path 
    splitted_path.each_with_index do |node, i| 
    if i != size - 1 
     # current node is path 
     # detect if it is already in the array 
     unless current_level.detect { |n| n['name'] == node } 
     # if not - append it to array 
     current_level << { 
      'name' => node, 
      'title' => node, 
      'isDir' => true, 
      'children' => [] 
     } 
     end 
     # set the current level to the new node's children array 
     current_level = current_level.detect { |n| n['name'] == node }['children'] 
    else 
     # node is a file - append it to the children array on current level 
     current_level << { 
     'name' => node, 
     'title' => node 
     } 
    end 
    end 
end 

tree 
+0

它看起來不錯。我只是用更多的例子和角落案例來驗證它。非常感謝+1 – shivam 2014-09-05 08:52:37

2

我喜歡選擇更模塊化的方法。首先,我要建立一個方法make_tree其的文件路徑的列表轉換成嵌套散列:

require 'pathname' 

def insert_node(tree, parts) 
    head, *tail = parts 
    tree[head] ||= {} 
    insert_node tree[head], tail unless tail.empty? 
    tree 
end 

def make_tree(paths) 
    paths.reduce({}) do |tree, file| 
    insert_node tree, Pathname(file).each_filename.to_a 
    end 
end 

下面是一個例子 - 這個輸出將僅被用作中間結果以後:

paths = ["./a.txt", "./b.txt", "./bar/z.php", "./foo/hello/y.php", "./foo/x.php"] 
tree = make_tree(paths) 
#=> {"."=> 
# {"a.txt"=>{}, 
#  "b.txt"=>{}, 
#  "bar"=>{"z.php"=>{}}, 
#  "foo"=>{"hello"=>{"y.php"=>{}}, "x.php"=>{}}}} 

然後,我們可以寫一個函數來此嵌套哈希轉換成「dynatree」表示:

def make_dynatree(tree) 
    tree.map do |node, subtree| 
    if subtree.empty? 
     {"name" => node, "title" => node} 
    else 
     {"name" => node, "title" => node, "isDir" => true, "children" => make_dynatree(subtree)} 
    end 
    end 
end 

最後:

dynatree = make_dynatree(tree) 
#=> [{"name"=>".", "title"=>".", "isDir"=>true, "children"=> 
#  [{"name"=>"a.txt", "title"=>"a.txt"}, 
#  {"name"=>"b.txt", "title"=>"b.txt"}, 
#  {"name"=>"bar", "title"=>"bar", "isDir"=>true, "children"=>[ 
#  {"name"=>"z.php", "title"=>"z.php"}]}, 
#  {"name"=>"foo", "title"=>"foo", "isDir"=>true, "children"=>[ 
#  {"name"=>"hello", "title"=>"hello", "isDir"=>true, "children"=>[ 
#   {"name"=>"y.php", "title"=>"y.php"}]}, 
#   {"name"=>"x.php", "title"=>"x.php"}]}]}] 
+0

這看起來很棒!同時易於理解 – shivam 2014-09-05 10:13:55

+0

清理它更多... – 2014-09-05 11:37:09