2013-03-18 33 views
0

考慮下面的輸入(從CSV文件):轉彎列表節點返回到樹結構中的Ruby

input = [ 
    { :level => 0, :value => "a" }, 
    { :level => 1, :value => "1" }, 
    { :level => 1, :value => "2" }, 
    { :level => 2, :value => "I" }, 
    { :level => 2, :value => "II" }, 
    { :level => 2, :value => "III" }, 
    { :level => 0, :value => "b" }, 
    { :level => 0, :value => "c" }, 
    { :level => 0, :value => "d" }, 
    { :level => 1, :value => "3" }, 
    { :level => 1, :value => "4" }, 
] 

我怎樣才能將它轉換爲在「Ruby之道」以下內容:

expected = [ 
    { :value => "a", :children => [ { :value => 1, :children => nil }, 
            { :value => 2, :children => [ { :value => "I", :children => nil }, 
                   { :value => "II", :children => nil }, 
                   { :value => "III", :children => nil } ] } ] }, 
    { :value => "b", :children => nil }, 
    { :value => "c", :children => nil }, 
    { :value => "d", :children => [ { :value => 3, :children => nil }, 
            { :value => 4, :children => nil } ] }, 
    ] 

編輯:

我對這個解決辦法是迴避問題,改造它,讓別人來解決它:

require 'yaml' 
def linear_to_tree(a) 
    yaml_lines = [] 

    a.each do |el| 
    indent = " " * 4 * el[:level] 
    yaml_lines << "#{indent}-" 
    yaml_lines << "#{indent} :value: #{(el[:value])}" 
    yaml_lines << "#{indent} :children:" 
    end 
    yaml_lines << "" # without this, YAML.load complains 
    yaml = yaml_lines.join("\n") 
    # open("test_yaml.txt", "w"){|f| f.write(yaml)} 
    YAML.load(yaml) 
end 

但一定要解決這個更優雅的方式。

P.S.我也希望看到這種轉變的單線,只是爲了看看是否有可能。

+0

沒有,__someone else__是'Yaml'解析器。 – Orangenhain 2013-03-18 23:23:02

+0

所以這些基本上是按「深度優先」順序排列的? – rogerdpack 2013-03-18 23:55:33

+0

是的。 (至少我從我見過的CSV中看到這一點。) – Orangenhain 2013-03-19 00:00:36

回答

0

對於沒有子節點的節點,應該使用空數組,空數組是一個集合的空對象。否則,當你分配它的時候,以及你什麼時候使用它的時候,你都必須跳舞。

def transform(inputs) 
    transform! inputs.dup 
end 

def transform!(inputs, output=[], current_level=0) 
    while inputs.any? 
    input = inputs.shift 
    level, value = input.values_at :level, :value 
    value = value.to_i if value =~ /\A\d+\z/ 
    if level < current_level 
     inputs.unshift input 
     break 
    elsif level == current_level 
     next_children = [] 
     output << {value: value, children: next_children} 
     transform! inputs, next_children, current_level.next 
    else 
     raise "presumably should not have gotten here" 
    end 
    end 
    output 
end