Tree view hierarchy

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

On 12/21/06, Patrick S. [email protected] 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”)

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

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!

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

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