2012-10-29 8 views
4

경로 정보가있는 플랫 배열을 해당 배열의 트리 표현으로 변환하는 함수를 작성하려고합니다. 이런 일에루비 : 트리 표현으로 평면 배열 변환

[ 
{ :name => "a", :path => [ 'a' ] }, 
{ :name => "b", :path => [ 'a', 'b' ] }, 
{ :name => "c", :path => [ 'a', 'b', 'c' ] }, 
{ :name => "d", :path => [ 'a', 'd' ] }, 
{ :name => "e", :path => [ 'e' ] } 
] 

:

:

[{: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=>[]}] 

나는 다음과 같은 코드로했다으로 가지고 가장 가까운 결과를

목표는 다음과 같은 배열을 설정하는 것입니다

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) 

그러나 그것은 매우 장황하고 나는 아주 어릴 때 그다지 효과적이지 않을 것이라고 생각합니다. ge 세트.

루비에서 가장 깨끗하고 효과적인 방법은 무엇입니까?

+4

나쁜 것으로 생각 되더라도 게시 할 항목. –

+0

질문에 설명되지 않은 방법이나 변수를 사용하지 마십시오. '경로'란 무엇입니까? – sawa

+0

@sawa 죄송합니다. 오타였습니다. 경로는 상징입니다. – Eric

답변

2

내 시도입니다.

array = [ 
{ :name => "a", :path => [ 'a' ] }, 
{ :name => "b", :path => [ 'a', 'b' ] }, 
{ :name => "c", :path => [ 'a', 'b', 'c' ] }, 
{ :name => "d", :path => [ 'a', 'd' ] }, 
{ :name => "e", :path => [ 'e' ] } 
] 

array 
.sort_by{|h| -h[:path].length} 
.map{|h| {node: h, children: []}} 
.tap{|array| 
    while array.first[:node][:path].length > 1 
    child = array.shift 
    array 
    .find{|h| h[:node][:name] == child[:node][:path][-2]}[:children] 
    .push(child) 
    end 
} 

# => [ 
    {:node=>{:name=>"e", :path=>["e"]}, :children=>[]}, 
    {:node=>{:name=>"a", :path=>["a"]}, :children=>[ 
    {:node=>{:name=>"d", :path=>["a", "d"]}, :children=>[]}, 
    {:node=>{:name=>"b", :path=>["a", "b"]}, :children=>[ 
     {:node=>{:name=>"c", :path=>["a", "b", "c"]}, :children=>[]} 
    ]} 
    ]} 
] 
+0

루비는 때로는 마법 같은 느낌입니다. 깨끗하고 효과적인. 고마워요! – Eric