Skip to content

Instantly share code, notes, and snippets.

@wisnij
Last active December 21, 2018 21:11
Show Gist options
  • Save wisnij/632cd061c7a1c20956505c90855a9a9e to your computer and use it in GitHub Desktop.
Save wisnij/632cd061c7a1c20956505c90855a9a9e to your computer and use it in GitHub Desktop.
Function for printing tree structures as text
=pod
B<print_tree>($I<ROOT>, \&I<PROCESS_NODE>)
Prints a textual representation of a hierarchical tree structure.
I<ROOT> is the top-level node in the tree.
I<PROCESS_NODE> is a subroutine reference which is called for each node in the
tree. It is given one argument, which is the current node; C<$_> is also
locally set to the same value. The subroutine should return one or more values:
the first being the string to print for that node's entry in the tree, and the
rest being any child nodes that descend from it.
For example:
my $tree = [
0,
[1,
[11,
[111, [1111], [1112]]],
[12,
[121]]],
[2,
[21,
[211], [212]]],
];
print_tree($tree, sub { @$_ });
0
|_ 1
| |_ 11
| | \_ 111
| | |_ 1111
| | \_ 1112
| \_ 12
| \_ 121
\_ 2
\_ 21
|_ 211
\_ 212
=cut
my $blank = ' ';
my $vert = '| ';
my $branch = '|_ ';
my $branch_last = '\\_ ';
sub print_tree
{
my ($tree, $process_node) = @_;
my @stack = ([$tree]);
my @delims;
while (@stack)
{
my $depth = $#stack;
my $nodes = $stack[$depth];
if (not @$nodes)
{
pop @stack;
pop @delims;
next;
}
my $node = shift @$nodes;
my $is_last = (@$nodes == 0);
my $leader = join '', @delims;
$leader .= ($is_last ? $branch_last : $branch)
if $depth > 0;
my ($label, @children) = do {
local $_ = $node;
$process_node->($node);
};
print $leader, $label // '(undef)', "\n";
if (@children)
{
push @stack, \@children;
push @delims, ($is_last ? $blank : $vert)
if $depth > 0;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment