in reply to (cLive ;-) Re: representing a tree graphically...
in thread representing a tree graphically...

Okay, a couple of things...

  1. I don't really understand your example of "$page->[$id]->{'parent'}". I don't see how that's a hash of hashes.

  2. I underestimated the problem, because of the "|" issue. When I've seen this problem before, the only important issues were:
    1. Nest/tab the children properly
    2. Do something special for hte first/last child
    An example of "pipeless" output is in the method "render_node_nopipe" below

  3. Even with the pipes, I still think it's cleaner to use a recursive method -- BUT, instead of passing an "indent" depth, you pass an acctuall padding string, that contains the pipes. The only real new complexity is that when dealing with each node, it's not enough to know if that node is the last of it's siblings, you also have to know if it's parent was the last of it's siblings (in order to build up the padding string properly).
    An example of the recursive solution is the method "render_node" below.

  4. It should be clear how to make this generate the appropriate HTML (<img src..>) output by modifing the single letter vars.

#!/usr/local/bin/perl -w use strict; my $d = " #"; my $t = " +"; my $l = " \\"; my $p = " |"; my $s = " "; my $tree = { 'one' => { 'two' => { 'five' => { 'boo' => { 'baz' => { }, }, }, }, 'three' => { 'four' => { }, 'yak' => { }, 'six' => { 'foo' => { 'yuk' => { }, }, 'ggg' => { }, }, }, }, }; print "with pipes...\n" . &render_node($tree->{'one'}, 'one'); print "no pipes...\n" . &render_node_tab($tree->{'one'}, 'one'); sub render_node { my ($tree, $node, $tok, $pad, $last) = @_; $tok = $s unless defined $tok; $pad = "" unless defined $pad; $last = 1 unless defined $last; my $out = $pad . $tok . $d . $node . "\n"; my @kids = sort keys %{$tree}; for (my $i = 0; $i < scalar @kids; $i++) { my $knode = $kids[$i]; my $ktree = $tree->{$knode}; my $klast = ($i+1 == scalar @kids); my $ktok = ($klast ? $l : $t); my $kpad = $pad . ($last ? $s : $p); $out .= &render_node($ktree, $knode, $ktok, $kpad, $klast); } return $out; } sub render_node_tab { my ($tree, $node, $tok, $indent) = @_; $tok = $s unless defined $tok; $indent = 0 unless defined $indent; my $out = ($s x $indent) . $tok . $d . $node . "\n"; my @kids = sort keys %{$tree}; for (my $i = 0; $i < scalar @kids; $i++) { my $knode = $kids[$i]; my $ktree = $tree->{$knode}; my $ktok = ($i+1 == scalar @kids) ? $l : $t; my $kindent = $indent+1; $out .= &render_node_tab($ktree, $knode, $ktok, $kindent); } return $out; } __END__ with pipes... #one + #three | + #four | + #six | | + #foo | | | \ #yuk | | \ #ggg | \ #yak \ #two \ #five \ #boo \ #baz no pipes... #one + #three + #four + #six + #foo \ #yuk \ #ggg \ #yak \ #two \ #five \ #boo \ #baz

Replies are listed 'Best First'.
(cLive ;-) Re: representing a tree graphically...
by cLive ;-) (Prior) on Jan 10, 2002 at 01:09 UTC
    Re 1: Hash starts off as $page->{$id}-{'parent'}, but for readability's sake I created a second, ordered array of hashes that was the original IDs mapped to an array index showing the correct display order (ie, sorted by 'treepath'). It was just easier to visualise.

    Nice code, but one thing's not as it should be (which I implied, but didn't specify *explicitly* before). I need the nodes to display in order (to allow users to build the order they want pages displayed in when menus are drawn, so they need to be sorted by 'treepath', eg:

    #one + #two | \ #five | \ #boo | \ #baz \ #three + #four + #yak \ #six + #foo | \ #yuk \ #ggg
    and not the re-ordered way that your code outputs the tree at the moment, if that makes sense.

    But thanks for the insight. I'll have a little play with the ideas you presented.

    cLive ;-)

      i just used the stock "sort" but you could easily drop in any sort method, as long as the criteria for sorting was something htat could be looked up using the node name (or a property of hte node object if you used proper objects)