我有一个数组,其中包含像这样的项目列表
arr = [
{:id=>1, :title=>"A", :parent_id=>nil},
{:id=>2, :title=>"B", :parent_id=>nil},
{:id=>3, :title=>"A1", :parent_id=>1},
{:id=>4, :title=>"A2", :parent_id=>1},
{:id=>5, :title=>"A11", :parent_id=>3},
{:id=>6, :title=>"12", :parent_id=>3},
{:id=>7, :title=>"A2=121", :parent_id=>6},
{:id=>8, :title=>"A21", :parent_id=>4},
{:id=>9, :title=>"B11", :parent_id=>2},
{:id=>10, :title=>"B12", :parent_id=>2},
...
]
如果parent_id
是nil
,那么它应该是父节点,如果parent_id
不是nil
那么它应该属于特定的父节点。
根据id
和parent_id
,我想提供这样的回复:
-A
-A1
-A11
-A12
-A123
-A2
-A21
-B
-B1
-B11
-B12
我怎样才能生成上面提到的回复?
由于
答案 0 :(得分:7)
你可以使用像Closure_tree这样的宝石:
hash_tree
提供了一种将子树渲染为有序的方法 嵌套哈希:Tag.hash_tree #=> {a => {b => {c1 => {d1 => {}}, c2 => {d2 => {}}}, b2 => {}}}
或Ancestry:
Ancestry可以将整个子树排列成嵌套的哈希,以方便使用 从数据库中检索后导航。
TreeNode.arrange
可以 例如return:{ #<TreeNode id: 100018, name: "Stinky", ancestry: nil> => { #<TreeNode id: 100019, name: "Crunchy", ancestry: "100018"> => { #<TreeNode id: 100020, name: "Squeeky", ancestry: "100018/100019"> => {} } } }
有关其他宝石,请参阅https://www.ruby-toolbox.com/categories/Active_Record_Nesting。
如果你必须在内存中这样做,这样的事情应该有效:
nested_hash = Hash[arr.map{|e| [e[:id], e.merge(children: [])]}]
nested_hash.each do |id, item|
parent = nested_hash[item[:parent_id]]
parent[:children] << item if parent
end
tree = nested_hash.select { |id, item| item[:parent_id].nil? }.values
require 'pp'
pp tree
输出
[{:id=>1,
:title=>"A",
:parent_id=>nil,
:children=>
[{:id=>3,
:title=>"A1",
:parent_id=>1,
:children=>
[{:id=>5, :title=>"A11", :parent_id=>3, :children=>[]},
{:id=>6,
:title=>"12",
:parent_id=>3,
:children=>
[{:id=>7, :title=>"A2=121", :parent_id=>6, :children=>[]}]}]},
{:id=>4,
:title=>"A2",
:parent_id=>1,
:children=>[{:id=>8, :title=>"A21", :parent_id=>4, :children=>[]}]}]},
{:id=>2,
:title=>"B",
:parent_id=>nil,
:children=>
[{:id=>9, :title=>"B11", :parent_id=>2, :children=>[]},
{:id=>10, :title=>"B12", :parent_id=>2, :children=>[]}]}]
答案 1 :(得分:4)
一个例子:
#!/usr/bin/env ruby
root = {:id => 0, :title => '', :parent_id => nil}
arr = arr = [
{:id=>1, :title=>"A", :parent_id=>nil},
{:id=>2, :title=>"B", :parent_id=>nil},
{:id=>3, :title=>"A1", :parent_id=>1},
{:id=>4, :title=>"A2", :parent_id=>1},
{:id=>5, :title=>"A11", :parent_id=>3},
{:id=>6, :title=>"12", :parent_id=>3},
{:id=>7, :title=>"A2=121", :parent_id=>6},
{:id=>8, :title=>"A21", :parent_id=>4},
{:id=>9, :title=>"B11", :parent_id=>2},
{:id=>10, :title=>"B12", :parent_id=>2},
]
map = {}
arr.each do |e|
map[e[:id]] = e
end
@@tree = {}
arr.each do |e|
pid = e[:parent_id]
if pid == nil || !map.has_key?(pid)
(@@tree[root] ||= []) << e
else
(@@tree[map[pid]] ||= []) << e
end
end
def print_tree(item, level)
items = @@tree[item]
unless items == nil
indent = level > 0 ? sprintf("%#{level * 2}s", " ") : ""
items.each do |e|
puts "#{indent}-#{e[:title]}"
print_tree(e, level + 1)
end
end
end
print_tree(root, 0)
输出:
-A
-A1
-A11
-12
-A2=121
-A2
-A21
-B
-B11
-B12
答案 2 :(得分:2)
并不是要取代经过验证的宝石,但根据您的需要,您可以使用以下简单的东西:
groups = arr.group_by{ |x| x[:parent_id] }
groups.default = []
build_tree =
lambda do |parent|
[parent[:title], groups[parent[:id]].map(&build_tree)]
# or
# { parent[:title] => groups[parent[:id]].map(&build_tree) }
end
p build_tree[:id => nil][1] # :id => nil is not required, empty hash will work too
# => [["A", [["A1", [["A11", []], ["A12", [["A122", []]]]]], ["A2", [["A21", []]]]]], ["B", [["B11", []], ["B12", []]]]]