This is a common pattern. The basic problem is "how to I generate a child pointer tree from a parent pointer representation (as would normally be stored in a DB)". The following is a (proven but not debugged) solution that doesnt require multiple queries, can handle the data in any order, and only requires a single forward pass over the data.
sub getCategories { my ($dbh)=@_; my $sql = qq~SELECT category_id, parent_id, category_name FROM ss_ +catalog_categories~; my $sth = $dbh->prepare($sql); $sth->execute; my %nodes; my @roots; my ($cid,$pid,$name); while ( ($cid,$pid,$name) = $sth->fetchrow_array()) { my $node=($nodes{$cid}||={}); $node->{name}=$name; $node->{pid}=$pid; $node->{cid}=$cid; if ($pid) { $nodes{$pid}{_kids}{$cid}=$node; } else { push @roots,$node; } } $sth->finish; return (\@roots,\%nodes); }
Roots contains the root nodes of your forest, and %nodes contains a hash keyed by the category id of the nodes. You can traverse each tree in the forest like this:
sub traverse { my ($node,$depth)=@_; $depth||=0; print " " x $depth,$node->{cid}," ",$node->{name},"\n"; foreach my $id ( sort {$a <=> $b} keys %{$node->{_kids}||{}} ) { traverse($node->{_kids}{$id},$depth+1); } } my ($r,$n)=getCategories($dbh); traverse($_) for sort { $a->{cid} <=> $b->{cid} } @$r;
For those that care the above code is a highly simplified form of what is used here for the Recently Active Threads.
In reply to Re: Nested Categories (Aka: How to build a child pointer tree from a parent pointer representation)
by demerphq
in thread Nested Categories
by spaceout
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |