in reply to Printing a tree-view of a hash of hashes

Your specification is rather sparse. However a big heads up in your code is that you are using nested loops. That just ain't going to work. Every time you add a level to your hash you will need to add another nested loop and you really don't want to go there.

The common technique is to write a recursive sub to do the work. Consider:

use strict; use warnings; use 5.010; my %categories = ( level1 => { 'level1-1' => {}, 'level1-2' => {'level1-2-1' => {}}, 'level1-3' => {}, }, level2 => {'level2-1' => {}}, ); dumpHash(\%categories); sub dumpHash { my ($subHash, $indent) = @_; $indent //= ''; given (ref $subHash) { when ('') {print "$indent$subHash\n" if defined $subHash} when ('HASH') { for my $key (sort keys %$subHash) { print "$indent$key\n"; dumpHash($subHash->{$key}, "$indent "); } } } }

Prints:

level1 level1-1 level1-2 level1-2-1 level1-3 level2 level2-1
True laziness is hard work

Replies are listed 'Best First'.
Re^2: Printing a tree-view of a hash of hashes
by pdxperl (Sexton) on Jun 01, 2010 at 03:24 UTC
    Thanks -- btw, this works correctly! The other recursive example goes into an infinite loop. I'm not sure why, but at least I'm over one roadblock.

      The other recursive example goes into an infinite loop.

      I presume you mean mine. If so, no it doesn't:

      use strict; use warnings; sub print_tree { my ($tree, $depth) = @_; $depth ||= 0; my $indent = '...' x $depth; for (sort keys %$tree) { print($indent, /^\s*\z/ ? "<blank>" : $_, "\n"); print_tree($tree->{$_}, $depth+1); } } my %categories = ( level1 => { 'level1-1' => {}, 'level1-2' => {'level1-2-1' => {}}, 'level1-3' => {}, }, level2 => {'level2-1' => {}}, ); print_tree(\%categories);
      level1 ...level1-1 ...level1-2 ......level1-2-1 ...level1-3 level2 ...level2-1

      Unless, of course, you don't actually a have tree. Like I said before, %categories doesn't contain what you think it does.

        Thanks -- I didn't mean that comment negatively, as I appreciate the help. Your example is fine with your data, but with mine it did appear to go into infinite recursion. And I agree, there is something odd with what's in the hash, but what I didn't understand was why was is OK in Data::Dumper? So I did track down the cause,which is boiled down to the testcase below. This is what strict was complaining about as the string ref error. I fixed the issue, however, I'm not sure why it causes the tree to be displayed so differently for my approach versus yours versus data dumper. I commented strict out so you can see how the display differs, I know strict normally shouldn't be commented out. Also, this is deliberately showing an error - I'm just showing the odd output that results from that error.
        #use strict; use Data::Dumper; my %h; $h{'B'}{1}=1; # this is the error which causes the display # issues for my $a ('A'..'C'){ for my $b (0..2){ for my $c ('a'..'c') { $h{$a}{$b}{$c}=1; # error if $h{$a}{$b} exists } } } print "Data Dumper-------------------\n"; print Dumper (\%h); print "Loop----------------\n"; foreach my $top ( sort keys %h){ if($top =~ /^\s*$/){$top="<blank>";} print "$top\n"; foreach my $second ( sort keys %{$h{$top}}){ if($second =~ /^\s*$/){$second="<blank>";} print "...$second\n"; foreach my $third (sort keys %{$h{$top}{$second}}){ if($third =~ /^\s*$/){$third="<blank>";} print "......$third\n"; } } } print "Print_tree------------------\n"; print_tree(\%h); sub print_tree { my ($tree, $depth) = @_; if($depth > 5) { print "max depth reached\n"; return; } $depth ||= 0; my $indent = '...' x $depth; for (sort keys %$tree) { print($indent, /^\s*\z/ ? "<blank>" : $_, "\n"); print_tree($tree->{$_}, $depth+1); } }