对象树遍历红宝石

时间:2012-11-14 15:55:22

标签: ruby

所以...我有以下内容:

具有从.xml文件检索的多个属性的类。如果对象是条件(它有两个子节点)及其名称,则这些属性。基本上,对象的子属性是其子项的名称。

.xml看起来像这样:

<object-2>
     <name>Object - 2</name>
     <yesChild>Object - 3</yesChild>
     <noChild>Object - 4</noChild>
</object-2>

如果noChild为空,则表示该对象不是条件。从.xml中检索的所有对象都存储在一个数组中。

我需要的是以某种方式从中创建一个树并识别可以采取的所有路径以便到达数组中的最后一个元素。该算法不需要遍历所有节点,只需要遍历到达阵列最后一个元素所需的节点。

示例:

我们有4个对象:X1,X2,X3和X4,其中X1是X2和X3作为其子元素的条件,那么我们将有2条路径从X1开始并以X4结束。 路径1:X1-> X2-> X4 路径2:X1-> X3-> X4

谢谢。

1 个答案:

答案 0 :(得分:0)

由于解析后没有显示数据的格式,我猜测:)以下是我将解析后的数据存储在ruby对象中的方法(为了清楚起见,使用新式的哈希键语法): / p>

[ {yes: 2, no: 3},
  {yes: 4},
  {yes: 4},
  {yes: -1} ]

然后,树遍历可以递归完成。只要您的数组长度不是数千个元素,这就可以正常工作。

def tree(object_number, list)
  if object_number == list.size
    [[object_number]]
  else
    list[object_number-1].values.map { |obj_num|
      tree(obj_num,list)
    }.inject{|a,b| a+b}.map{|l| [object_number] + l}
  end
end

现在你调用函数:

tree(1,data)
  => [[1, 2, 4], [1, 3, 4]]
data = [ {yes: 2, no: 3}, {yes: 4, no:5}, {yes:5, no:4}, {yes:5}, {yes: -1} ]
tree(1,data)
  => [[1, 2, 4, 5], [1, 2, 5], [1, 3, 5], [1, 3, 4, 5]]

工作原理: 构建此列表的最简单方法是向后,因为我们只知道路径的数量,一旦我们到达所有路径的末尾。所以这段代码一直跟着引用到最后,当它到达最后一个对象时,它将它作为单元素二维数组返回。

tree(5,list)
  => [[5]]

在每个递归级别,它接受它的递归调用的结果(作为列表列表返回)并将它自己的对象编号预先添加到每个内部列表中。所以,在备份树之后:

tree(4,list) # prepends 4 to tree(5)
  => [[4,5]]
tree(3,list) # prepends 3 to tree(4) and tree(5)
  => [[3,4,5],[3,5]]
tree(2,list) # prepends 2 to tree(4) and tree(5)
  => [[2,4,5],[2,5]]
tree(1,list) # prepends 1 to tree(2) and tree(3)
  => [[1, 2, 4, 5], [1, 2, 5], [1, 3, 5], [1, 3, 4, 5]]

如果列表可能足够长以溢出堆栈,则总是可以在没有递归的情况下执行此操作。递归是解决这个特殊问题的最简单方法。