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)] }