Re: Printing a tree-view of a hash of hashes
by GrandFather (Saint) on Jun 01, 2010 at 00:35 UTC
|
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
| [reply] [d/l] [select] |
|
|
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.
| [reply] |
|
|
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. | [reply] [d/l] [select] |
|
|
|
|
Re: Printing a tree-view of a hash of hashes
by ikegami (Patriarch) on Jun 01, 2010 at 00:36 UTC
|
as I see every third level element in the hash being printed, not just the third level elements associated with the current second level.
That's not possible from the code you printed. It would suggest that %categories doesn't contain what you think it does.
Note that there can be different levels of hierarchy
Sounds like you need a recursive solution.
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);
}
}
print_tree(\%categories);
| [reply] [d/l] [select] |
|
|
sub print_tree
{
my ($tree, $depth) = (@_, 0);
ref $tree eq "HASH" or return;
my $indent = "..." x $depth;
for (sort keys %$tree) {
print $indent, /^\s*\z/ ? "<blank>" : $_, "\n";
print_tree ($tree->{$_}, $depth + 1);
}
}
print_tree (\%categories);
Enjoy, Have FUN! H.Merijn
| [reply] [d/l] |
Re: Printing a tree-view of a hash of hashes
by tinita (Parson) on Jun 01, 2010 at 11:05 UTC
|
| [reply] |
Re: Printing a tree-view of a hash of hashes
by toolic (Bishop) on Jun 01, 2010 at 00:21 UTC
|
Post code that we can run to reproduce your failing case.
- Show us your input data (%categories).
- Show the exact output you get.
- Show the exact output you want to get.
| [reply] [d/l] |
|
|
OK, this is so odd I know it's something I'm going to be something dumb that I'll be embarrassed about. When I created the testcase, it works fine. When I run the complete program, there's a problem.
But here's why that's odd -- instead of posting a lot of code, Excel spreadsheets, etc, I just put a Data::Dumper command for %categories right before I did the print in the original program. Then I created the testcase, copied the output from Data::Dumper and just set %categories to the content of Data::Dumper, then did the print using the same code. Works fine!
Now if I run the original program, I see the output from Data::Dumper isn't changed -- but the final printed output is screwed up. I'm confused since the content of %categories looks EXACTLY the same!
(I do agree, would be better/more flexible to use recursion! However, the testcase works)
Here's the testcase and it's output:
So.. that's correct. No issues with how I'm reading the hash.
However in the main program, the output looks like this. Look at accessories->bookends -- a whole new level of hierarchy at the third level with lots of bogus info!
<etc... rest of the errors snipped>
| [reply] [d/l] [select] |
|
|
I get Can't use string ("1") as a HASH ref while "strict refs" in use. You seem to be hiding errors by not using use strict; use warnings;. no autovivification; would also be useful to you.
This kind of mistake elsewhere in your code would definitely explain your symptoms. You're placing all your data in one hash (%1), and you are linking to that hash throughout the tree.
I think your data structure is equivalent to the one below. It would also explain the infinite looping you are experiencing with the recursive solutions.
%{"1"} = (
cat2 => \%{"1"},
cat21 => \%{"1"},
cat22 => \%{"1"},
cat3 => \%{"1"},
);
my %category = (
cat1 => \%{"1"},
);
| [reply] [d/l] [select] |
Re: Printing a tree-view of a hash of hashes
by perreal (Monk) on Jun 01, 2010 at 10:23 UTC
|
I also noticed that then you assign <blank> to at least the second level elements, then you may end up attaching same third level elements to different 2nd level elements. | [reply] |