代码之家  ›  专栏  ›  技术社区  ›  shivam

从文件列表中,动态创建dynatree的哈希数组

  •  1
  • shivam  · 技术社区  · 11 年前

    我有一个按数组排序的文件列表,例如:

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

    如何从中创建动态树对象? 它的动态树对象应如下所示:

    [{"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多个小时来解决这个问题。因此,我们将非常感谢您的帮助。谢谢

    2 回复  |  直到 11 年前
        1
  •  2
  •   Patrick Oscity    11 年前

    我喜欢选择更模块化的方法。首先,我要建立一个方法 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"=>{}}}}
    

    然后,我们可以编写一个函数来将这个嵌套的哈希转换为“动态树”表示:

    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"}]}]}]
    
        2
  •  1
  •   Nikita Chernov    11 年前

    我的想法是遍历每个路径。每条路径由 / 将其分为若干部分。最后一部分是文件,其他-目录。

    除非已经添加了新目录,否则我会遍历每个部分添加新目录。在每次迭代结束时,我将上下文切换到下一个级别- 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