ruby如何生成树形结构表单数组?

我有一个数组,其中包含这样的项目列表

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_idnil那么它应该是父节点,如果parent_id不是nil则它应该在特定父节点下。

基于idparent_id ,我想提供这样的响应:

 -A -A1 -A11 -A12 -A123 -A2 -A21 -B -B1 -B11 -B12 

我怎么能产生上面提到的回应?

谢谢

一个例子:

 #!/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 

你可以使用像Closure_tree这样的gem:

hash_tree提供了一种将子树呈现为有序嵌套哈希的方法:

 Tag.hash_tree #=> {a => {b => {c1 => {d1 => {}}, c2 => {d2 => {}}}, b2 => {}}} 

或祖先 :

Ancestry可以将整个子树排列成嵌套哈希,以便在从数据库中检索后轻松导航。 TreeNode.arrange可以返回:

 { # => { # => { # => {} } } } 

有关其他gem,请参阅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=>[]}]}] 

并不是要取代经过validation的gem,但根据您的需要,您可以使用以下简单的方法:

 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", []]]]]