Ruby on rails 使用哈希数组的树节点

Ruby on rails 使用哈希数组的树节点,ruby-on-rails,ruby,ruby-on-rails-4,Ruby On Rails,Ruby,Ruby On Rails 4,我有以下哈希数组: [ {key: 1, reference: 'reference', path: '.../public/shared/file_1.txt', type: 'public'}, {key: 2, reference: 'reference', path: '.../public/shared/file_2.txt', type: 'public'}, {key: 3, reference: 'reference', path: '.../public/share

我有以下哈希数组:

[
  {key: 1, reference: 'reference', path: '.../public/shared/file_1.txt', type: 'public'},
  {key: 2, reference: 'reference', path: '.../public/shared/file_2.txt', type: 'public'},
  {key: 3, reference: 'reference', path: '.../public/shared/sub_folder/file_3.txt', type: 'public'},
  {key: 4, reference: 'reference', path: '.../public/shared/sub_folder/file_4.txt', type: 'public'},
  {key: 5, reference: 'reference', path: '.../log/file_5.txt', type: 'log'},
  {key: 5, reference: 'reference', path: '.../tmp/cache/file_6.txt', type: 'log'},
]
然后使用每个节点的路径结构,我想创建一个如下树:

[
  { 
    key: 'root', folder: true, title: 'root',
    children: [
                {
                  key: 'public', folder: true, title: 'public',
                  children: [
                              {
                                key: 'shared', folder: true, title: 'shared',
                                children: [ 
                                            { key: 1, title: 'file_1.txt' },
                                            { key: 2, title: 'file_2.txt' },
                                            {
                                              key: 'sub_folder', folder: true, title: 'sub_folder',
                                              children: [
                                                { key: 3, title: 'file_3.txt' },
                                                { key: 4, title: 'file_4.txt' }
                                              ]
                                            }
                                          ]
                              }
                            ]
                },
                {
                  key: 'log', folder: true, title: 'log', children: [ { key: 5, title: 'file_5.txt' } ]
                },
                {
                  key: 'tmp', folder: true, title: 'tmp',
                  children: [
                              { key: 'cache', folder: true, title: 'cache', children: [ { key: 6, title: 'file_6.txt' } }
                            ]
                }
              ]
  }
]

是否可以使用每个节点的路径创建该结构?我正在使用Ruby on Rails。

您可以这样定义类:


我提供了一个递归解决方案

代码

范例

我们现在可以从arr构建所需的阵列:

解释

示例中arr的步骤如下所示

内行

将其分解,我们执行以下计算

arr的第一个元素被传递到map的块,并成为块变量g`的值:

然后执行块计算

b = g[:path]
  #=> ".../public/shared/file_1.txt"
c = b[4..-1]
  #=> "public/shared/file_1.txt"
d = c.split('/')
  #=> ["public", "shared", "file_1.txt"]
e = ['root', *d]
  #=> ["root", "public", "shared", "file_1.txt"]
*front, last = e
  #=> ["root", "public", "shared", "file_1.txt"]
front
  #=> ["root", "public", "shared"]
last
  #=> "file_1.txt"
f = g[:key]
  #=>
[front, { key: f, title: last }]
  #=> [["root", "public", "shared"], {:key=>1, :title=>"file_1.txt"}]
  empty, non_empty =  v.partition { |d,_| d.empty? }
  empty
    #=> []
  non_empty
    #=> [[["public", "shared"], {:key=>1, :title=>"file_1.txt"}],
    #    [["public", "shared"], {:key=>2, :title=>"file_2.txt"}], 
    #    [["public", "shared", "sub_folder"], {:key=>3, :title=>"file_3.txt"}],
    #    [["public", "shared", "sub_folder"], {:key=>4, :title=>"file_4.txt"}],
    #    [["log"], {:key=>5, :title=>"file_5.txt"}],
    #    [["tmp", "cache"], {:key=>6, :title=>"file_6.txt"}]
    #   ]
  p = empty.map(&:last)
    #=> []
  { key: dir, folder: true, title: dir,
    children: [*p, *recurse(non_empty)] }
    #=> { key: 'root', folder: true, title: 'root',
    #     children: [*[], *recurse(non_empty)] }
arr其余元素的映射类似

上面的数组a被传递给递归。第一步是删除作为目录数组的任何元素[d,h]d,h是d为空的散列。这是一项技术要求,在将一个或多个哈希值添加到数组(即:children的值)后,需要在递归中进行更深入的操作

下一步是将m的元素[dirs,h]按dirs的第一个元素分组。我在下面的块中使用了dirs.shift来从数组dirs中删除该元素

n的第一个元素现在被传递到map的块,块变量被分配:

dir, v = n.first
  #=> ["root", [
  #      [["public", "shared"], {:key=>1, :title=>"file_1.txt"}],
  #      [["public", "shared"], {:key=>2, :title=>"file_2.txt"}], 
  #      [["public", "shared", "sub_folder"], {:key=>3, :title=>"file_3.txt"}],
  #      [["public", "shared", "sub_folder"], {:key=>4, :title=>"file_4.txt"}],
  #      [["log"], {:key=>5, :title=>"file_5.txt"}],
  #      [["tmp", "cache"], {:key=>6, :title=>"file_6.txt"}]
  #    ]
  #   ]
dir
  #=> "root"
v #=> [[["public", "shared"], {:key=>1, :title=>"file_1.txt"}],
  #    ...
  #    [["tmp", "cache"], {:key=>6, :title=>"file_6.txt"}]
  #   ]
然后执行块计算

b = g[:path]
  #=> ".../public/shared/file_1.txt"
c = b[4..-1]
  #=> "public/shared/file_1.txt"
d = c.split('/')
  #=> ["public", "shared", "file_1.txt"]
e = ['root', *d]
  #=> ["root", "public", "shared", "file_1.txt"]
*front, last = e
  #=> ["root", "public", "shared", "file_1.txt"]
front
  #=> ["root", "public", "shared"]
last
  #=> "file_1.txt"
f = g[:key]
  #=>
[front, { key: f, title: last }]
  #=> [["root", "public", "shared"], {:key=>1, :title=>"file_1.txt"}]
  empty, non_empty =  v.partition { |d,_| d.empty? }
  empty
    #=> []
  non_empty
    #=> [[["public", "shared"], {:key=>1, :title=>"file_1.txt"}],
    #    [["public", "shared"], {:key=>2, :title=>"file_2.txt"}], 
    #    [["public", "shared", "sub_folder"], {:key=>3, :title=>"file_3.txt"}],
    #    [["public", "shared", "sub_folder"], {:key=>4, :title=>"file_4.txt"}],
    #    [["log"], {:key=>5, :title=>"file_5.txt"}],
    #    [["tmp", "cache"], {:key=>6, :title=>"file_6.txt"}]
    #   ]
  p = empty.map(&:last)
    #=> []
  { key: dir, folder: true, title: dir,
    children: [*p, *recurse(non_empty)] }
    #=> { key: 'root', folder: true, title: 'root',
    #     children: [*[], *recurse(non_empty)] }
最后一个键:children的值减少为[*recursenon_empty]。如图所示,递归现在被递归调用,参数为非空


其余的计算是类似的,但是当递归被传递给一个数组,该数组具有一个或多个元素,其中dirs数组包含单个元素,导致相关的哈希被添加到一个数组中,该数组是key:children的值。要完全理解计算,可能需要在代码中添加一些puts语句。

如果文件名不需要后缀,则可能需要一个小的mod。
  g = arr.first
    #=> {:key=>1, :reference=>"reference",
    #    :path=>".../public/shared/file_1.txt", :type=>"public"}
b = g[:path]
  #=> ".../public/shared/file_1.txt"
c = b[4..-1]
  #=> "public/shared/file_1.txt"
d = c.split('/')
  #=> ["public", "shared", "file_1.txt"]
e = ['root', *d]
  #=> ["root", "public", "shared", "file_1.txt"]
*front, last = e
  #=> ["root", "public", "shared", "file_1.txt"]
front
  #=> ["root", "public", "shared"]
last
  #=> "file_1.txt"
f = g[:key]
  #=>
[front, { key: f, title: last }]
  #=> [["root", "public", "shared"], {:key=>1, :title=>"file_1.txt"}]
m = a.reject { |dirs, _| dirs.empty? }
  #=> a (no elements are removed)
n = m.group_by { |dirs,_| dirs.shift }
  #=> {"root"=>[ 
  #     [["public", "shared"], {:key=>1, :title=>"file_1.txt"}],
  #     [["public", "shared"], {:key=>2, :title=>"file_2.txt"}],
  #     [["public", "shared", "sub_folder"], {:key=>3, :title=>"file_3.txt"}],
  #     [["public", "shared", "sub_folder"], {:key=>4, :title=>"file_4.txt"}],
  #     [["log"], {:key=>5, :title=>"file_5.txt"}],
  #     [["tmp", "cache"], {:key=>6, :title=>"file_6.txt"}]
  #    ]
  #   }
dir, v = n.first
  #=> ["root", [
  #      [["public", "shared"], {:key=>1, :title=>"file_1.txt"}],
  #      [["public", "shared"], {:key=>2, :title=>"file_2.txt"}], 
  #      [["public", "shared", "sub_folder"], {:key=>3, :title=>"file_3.txt"}],
  #      [["public", "shared", "sub_folder"], {:key=>4, :title=>"file_4.txt"}],
  #      [["log"], {:key=>5, :title=>"file_5.txt"}],
  #      [["tmp", "cache"], {:key=>6, :title=>"file_6.txt"}]
  #    ]
  #   ]
dir
  #=> "root"
v #=> [[["public", "shared"], {:key=>1, :title=>"file_1.txt"}],
  #    ...
  #    [["tmp", "cache"], {:key=>6, :title=>"file_6.txt"}]
  #   ]
  empty, non_empty =  v.partition { |d,_| d.empty? }
  empty
    #=> []
  non_empty
    #=> [[["public", "shared"], {:key=>1, :title=>"file_1.txt"}],
    #    [["public", "shared"], {:key=>2, :title=>"file_2.txt"}], 
    #    [["public", "shared", "sub_folder"], {:key=>3, :title=>"file_3.txt"}],
    #    [["public", "shared", "sub_folder"], {:key=>4, :title=>"file_4.txt"}],
    #    [["log"], {:key=>5, :title=>"file_5.txt"}],
    #    [["tmp", "cache"], {:key=>6, :title=>"file_6.txt"}]
    #   ]
  p = empty.map(&:last)
    #=> []
  { key: dir, folder: true, title: dir,
    children: [*p, *recurse(non_empty)] }
    #=> { key: 'root', folder: true, title: 'root',
    #     children: [*[], *recurse(non_empty)] }