I am trying to write a function to convert a flat array with a path information into a tree representation of that array.
The goal would be to turn an array like the following:
[
{ :name => "a", :path => [ 'a' ] },
{ :name => "b", :path => [ 'a', 'b' ] },
{ :name => "c", :path => [ 'a', 'b', 'c' ] },
{ :name => "d", :path => [ 'a', 'd' ] },
{ :name => "e", :path => [ 'e' ] }
]
into one like this:
[{:node=>{:name=>"a", :path=>["a"]},
:children=>
[{:node=>{:name=>"b", :path=>["a", "b"]},
:children=>
[{:node=>{:name=>"c", :path=>["a", "b", "c"]}, :children=>[]}]},
{:node=>{:name=>"d", :path=>["a", "d"]}, :children=>[]}]},
{:node=>{:name=>"e", :path=>["e"]}, :children=>[]}]
The closest result I got with was with the following code:
class Tree
def initialize
@root = { :node => nil, :children => [ ] }
end
def from_array( array )
array.inject(self) { |tree, node| tree.add(node) }
@root[:children]
end
def add(node)
recursive_add(@root, node[:path].dup, node)
self
end
private
def recursive_add(parent, path, node)
if(path.empty?)
parent[:node] = node
return
end
current_path = path.shift
children_nodes = parent[:children].find { |child| child[:node][:path].last == current_path }
unless children_nodes
children_nodes = { :node => nil, :children => [ ] }
parent[:children].push children_nodes
end
recursive_add(children_nodes, path, node)
end
end
flat = [
{ :name => "a", :path => [ 'a' ] },
{ :name => "b", :path => [ 'a', 'b' ] },
{ :name => "c", :path => [ 'a', 'b', 'c' ] },
{ :name => "d", :path => [ 'a', 'd' ] },
{ :name => "e", :path => [ 'e' ] }
]
require 'pp'
pp Tree.new.from_array( flat )
But it is quite verbose and I have the feeling that it might not be very effective for very large sets.
What would be the cleanest and most effective way to achieve that in ruby?
This is my try.