# Tree view hierarchy

**URL:** <https://www.ruby-forum.com/t/tree-view-hierarchy/80119>\
**Category:** Ruby\
**Created:** [December 21, 2006, 3:46pm UTC](https://www.ruby-forum.com/t/tree-view-hierarchy/80119 "2006-12-21T15:46:29Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![pkspence](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/a88e57/32.png) [@pkspence](https://www.ruby-forum.com/u/pkspence)\
**Post date:** [December 21, 2006, 3:46pm UTC](https://www.ruby-forum.com/t/tree-view-hierarchy/80119/1 "2006-12-21T15:46:29Z")

</div>

Tree view displayed on web page looks like this:

Smoking  
Survey & Feedback  
Depression  
Survey & Feedback  
Stress Management  
Survey & Feedback  
Weight Management  
Exercise  
Survey & Feedback  
Healthy Eating  
Survey & Feedback  
Managing Emotions  
Survey & Feedback

Using the “className” property of each node, I am able to  
determine the hierarchy. After scraping the list of nodes  
from the page, I have an array that contains the following:

[  
[1, “Smoking”, “root”],  
[2, “Survey & Feedback”, “leaf”],  
[3, “Depression”, “root”],  
[4, “Survey & Feedback”, “leaf”],  
[5, “Stress Management”, “root”],  
[6, “Survey & Feedback”, “leaf”],  
[7, “Weight Management”, “root”],  
[8, “Exercise”, “parent”],  
[9, “Survey & Feedback”, “leaf”],  
[10, “Healthy Eating”, “parent”],  
[11, “Survey & Feedback”, “leaf”],  
[12, “Managing Emotions”, “parent”],  
[13, “Survey & Feedback”, “leaf”]  
]

What I need to do is iterate thru each element of the array,  
determining the parent and root nodes of each element,  
separating each level of the hierarchy with a pipe symbol.  
The end result would be an array that contains something  
like this:

[  
[“Smoking|Survey & Feedback”]  
[“Depression|Survey & Feedback”]  
[“Stress Management|Survey & Feedback”]  
[“Weight Management|Exercise|Survey & Feedback”],  
[“Weight Management|Healthy Eating|Survey & Feedback”],  
[“Weight Management|Managing Emotions|Survey & Feedback”]  
]

Anyone got any ideas on this?

TIA

---

<div class="post-metadata">

**Author:** ![pkspence](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/a88e57/32.png) [@pkspence](https://www.ruby-forum.com/u/pkspence)\
**Post date:** [December 21, 2006, 4:40pm UTC](https://www.ruby-forum.com/t/tree-view-hierarchy/80119/2 "2006-12-21T16:40:36Z")

</div>

On 12/21/06, Patrick S. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> What I need to do is iterate thru each element of the array,  
> determining the parent and root nodes of each element,  
> separating each level of the hierarchy with a pipe symbol.  
> The end result would be an array that contains something  
> like this:

Here’s something that might help. This code buils an actual tree,  
keeping track of the leaves, and lets the Node class worry about  
printing the correct names. The output needs to be tweaked a little if  
you want nested arrays, but it’s basically correct:

============

class Node  
def initialize(value, parent=nil, children=[])  
@value = value  
@parent = parent  
@children = children  
end

```
def to_s
    if @parent.nil?
        @value
    else
        @parent.to_s + "|" + @value
    end
end

def add_child(node)
    node.parent = self
    @children << node
end

attr_accessor :parent

```

end

array =  
[  
[1, “Smoking”, “root”],  
[2, “Survey & Feedback”, “leaf”],  
[3, “Depression”, “root”],  
[4, “Survey & Feedback”, “leaf”],  
[5, “Stress Management”, “root”],  
[6, “Survey & Feedback”, “leaf”],  
[7, “Weight Management”, “root”],  
[8, “Exercise”, “parent”],  
[9, “Survey & Feedback”, “leaf”],  
[10, “Healthy Eating”, “parent”],  
[11, “Survey & Feedback”, “leaf”],  
[12, “Managing Emotions”, “parent”],  
[13, “Survey & Feedback”, “leaf”]  
]

leaves = []

last\_root = nil  
last\_parent = nil

array.each do |current|

```
if ( current[2] == 'root')

    last_root = Node.new(current[1])

elsif ( current[2] == 'parent' )

    last_parent = Node.new(current[1])
    last_root.add_child(last_parent)

elsif ( current[2] == 'leaf' )

    leaves << Node.new(current[1])
    ( last_parent || last_root ).add_child( leaves.last )

end

```

end

puts leaves.join(“\n”)

---

<div class="post-metadata">

**Author:** ![pkspence](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/a88e57/32.png) [@pkspence](https://www.ruby-forum.com/u/pkspence)\
**Post date:** [December 21, 2006, 5:10pm UTC](https://www.ruby-forum.com/t/tree-view-hierarchy/80119/3 "2006-12-21T17:10:42Z")

</div>

On Dec 21, 2006, at 9:44 AM, Patrick S. wrote:

> What I need [is] an array that contains something like this:
> 
> [  
> [“Smoking|Survey & Feedback”]  
> [“Depression|Survey & Feedback”]  
> [“Stress Management|Survey & Feedback”]  
> [“Weight Management|Exercise|Survey & Feedback”],  
> [“Weight Management|Healthy Eating|Survey & Feedback”],  
> [“Weight Management|Managing Emotions|Survey & Feedback”]  
> ]

First, if I was faced with this, I’d create a real tree structure, as  
Bira showed you, and generate the above list from that. If you need  
to do anything more than this example, or if there could be multiple  
levels of parent nodes, then a real tree would be much easier to use.

On the other hand, if you really just need that result, and the  
structure of your menu isn’t ever going to have more than one parent  
level, you could also do something like the following:

nodes = [  
[1, “Smoking”, “root”],  
…  
[13, “Survey & Feedback”, “leaf”]  
]

root = []  
parent = []  
leaves = []  
nodes.each do |node|  
idx, title, type = \*node  
case type  
when ‘root’  
root = [title]  
parent = []  
when ‘parent’  
parent = [title]  
when ‘leaf’  
leaves \<\< (root + parent + [title]).join(’|’)  
end  
end

At the end, ‘leaves’ will hold the list you wanted.

Cheers,

TomP

---

<div class="post-metadata">

**Author:** ![pkspence](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/a88e57/32.png) [@pkspence](https://www.ruby-forum.com/u/pkspence)\
**Post date:** [December 21, 2006, 5:30pm UTC](https://www.ruby-forum.com/t/tree-view-hierarchy/80119/4 "2006-12-21T17:30:47Z")

</div>

> On the other hand, if you really just need that result, and the  
> structure of your menu isn’t ever going to have more than one parent  
> level, you could also do something like the following:  
>   
> Unless I misunderstood… the Weight Management “root” node has  
> multiple “parent” level nodes. So, with that said, it would appear that  
> Bira’s solution fits the bill.

Thanks again chaps!

---

<div class="post-metadata">

**Author:** ![pkspence](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/a88e57/32.png) [@pkspence](https://www.ruby-forum.com/u/pkspence)\
**Post date:** [December 21, 2006, 5:24pm UTC](https://www.ruby-forum.com/t/tree-view-hierarchy/80119/5 "2006-12-21T17:24:46Z")

</div>

This code absolutely rocks! Thanks Bira and Tom for your help!

---

<div class="post-metadata">

**Author:** ![pkspence](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/a88e57/32.png) [@pkspence](https://www.ruby-forum.com/u/pkspence)\
**Post date:** [December 21, 2006, 7:39pm UTC](https://www.ruby-forum.com/t/tree-view-hierarchy/80119/6 "2006-12-21T19:39:08Z")

</div>

On Dec 21, 2006, at 11:29 AM, Patrick S. wrote:

> > On the other hand, if you really just need that result, and the  
> > structure of your menu isn’t ever going to have more than one parent  
> > level, you could also do something like the following:  
> >   
> > Unless I misunderstood… the Weight Management “root” node has  
> > multiple “parent” level nodes.

It has multiple ‘parent’ nodes, but only one parent level. The  
snippet I provided handles that. However, if a parent could contain  
one or more lower-level parents, rather than just leaves, then my  
code wouldn’t work correctly anymore. (You could adapt it, easily  
enough, as long as each level was clearly labeled by type, but better  
to have general solution.)

TomP
