【问题标题】:Ruby: Transform a flat array in a tree representationRuby:在树表示中转换平面数组
【发布时间】:2013-07-12 18:24:55
【问题描述】:

我正在尝试编写一个函数来将带有路径信息的平面数组转换为该数组的树表示。

我们的目标是把一个数组变成如下:

[
{ :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 )

但它非常冗长,我觉得它对于非常大的集合可能不是很有效。

在 ruby​​ 中实现这一目标的最简洁和最有效的方法是什么?

【问题讨论】:

  • 发布你拥有的东西,即使你认为它不好。
  • 请不要在问题中使用无法解释的方法或变量。 path 是什么?
  • @sawa 抱歉,打错了。路径是一个符号。
  • 我认为你应该尝试简化你的树。例如如果名称是唯一的,则可以使用名称作为关键字,以便您轻松搜索。
  • @AndrewMarshall 感谢您的指点,我添加了我当前的来源。

标签: ruby tree


【解决方案1】:

这是我的尝试。

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

【讨论】:

  • Ruby 有时感觉就像魔法一样。干净有效。非常感谢!
猜你喜欢
  • 2018-09-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-19
  • 1970-01-01
  • 2015-11-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多