2013-03-18 62 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