Is there an easy way to count the # of keys in a hash of hashes?
e.g.
Say I have a hash like the following:
$myhash{key1}{key2}
I want to count the total number of keys in $myhash without looping
through the whole thing. The answer is typically #key1 x #key2
Taking this one step further, I would like to know if there's a way to
do the same for "higher depths" like
$myhash{key1}{key2}{key3} and so on...
It will be really cool if there is a built in function/perl module
that can do this.
I shouldn't post code like this so I won't any more. I guess it goes
into my archives as a backup for future reference. I was mainly interrested
in deep recursion.
Anyway, refactored here. The thrust was on the metrics of a deep structure,
but I added the hooks to do deep array/hash clearing. It is mainly an
exercise for me but if the metric code is taken out, its actually not much
to the recursion. Obviously, anything could be added to the recursion frame
to do all sorts of things.
Tested as well.
-sln
use strict;
use warnings;
use Data:
umper;
my @ar1 = ('autoTestSoftware001',{50 => 'autoTestSoftware050'});
my @ar2 = ('autoTestSoftware051',{100 => 'autoTestSoftware100'});
push @ar1, [ar1 => \@ar2];
#my $softwareListRef = [\(@ar1, @ar2)];
my $softwareListRef = {root => [\(@ar1, @ar2)]};
push @ar1, {SWLF => $softwareListRef};
print Dumper( $softwareListRef );
my $result = getVariableMetrics ($softwareListRef, 'purge' => 1);
print <<MSG;
Metrics:
Hashs = $result->{hashs}
Keys = $result->{keys}
Arrays = $result->{arrays}
Others = $result->{others}
Depth = $result->{depth}
MSG
for (keys %{$result->{hseen}}) {
print " Seen = $result->{hseen}{$_} x $_\n";
}
print Dumper( \@ar1 );
print Dumper( \@ar2 );
print Dumper( $softwareListRef );
exit (0);
## -------------
sub getVariableMetrics # '$var' can be anything
{
my ($var, @args) = @_;
$result =
{ # Scalar Results and misc vars:
hashs => 0, # total hashes
keys => 0, # total keys
arrays => 0, # total arrays
others => 0, # total others
level => 0, # current level
depth => 0, # max depth
purge => 0, # flag to purge
hseen => {} # stringed array/hash refs seen
};
if (@args) {
while (my ($name, $val) = splice (@args, 0, 2)) {
$name =~ s/^\s+//; $name =~ s/\s+$//;
if (lc $name eq 'purge') {
$result->{purge} = 1 if $val;
}
}
}
_GVM ($var, $result);
}
sub _GVM
{
my ($var, $result) = @_;
# Hash ref's
if ( ref ($var) eq 'HASH') {
return $result if ( ++$result->{hseen}{$var} > 1);
if ( ++$result->{level} > $result->{depth}) {
$result->{depth} = $result->{level}
}
$result->{hashs}++;
for (values %{$var}) {
# go deeper into the key value
$result->{keys}++;
_GVM ($_, $result);
}
$result->{level}--;
# deepest level here, hash can be deleted
%{$var} = () if ($result->{purge});
}
# Array ref's
elsif ( ref ($var) eq 'ARRAY') {
return $result if ( ++$result->{hseen}{$var} > 1);
if ( ++$result->{level} > $result->{depth}) {
$result->{depth} = $result->{level}
}
$result->{arrays}++;
for (@{$var}) {
# go deeper into array element
_GVM ($_, $result);
}
$result->{level}--;
# deepest level here, array can be deleted
@{$var} = () if ($result->{purge});
}
# Other scalars (add more processing here)
else {
$result->{others}++;
}
return $result;
}
__END__
$VAR1 = {
'root' => [
[
'autoTestSoftware001',
{
'50' => 'autoTestSoftware050'
},
[
'ar1',
[
'autoTestSoftware051',
{
'100' => 'autoTestSoftware100'
}
]
],
{
'SWLF' => $VAR1
}
],
$VAR1->{'root'}[0][2][1]
]
};
Metrics:
Hashs = 4
Keys = 4
Arrays = 4
Others = 5
Depth = 6
Seen = 1 x ARRAY(0x18c4abc)
Seen = 2 x HASH(0x18c529c)
Seen = 1 x HASH(0x22ab94)
Seen = 1 x ARRAY(0x182abbc)
Seen = 1 x HASH(0x22ac84)
Seen = 2 x ARRAY(0x182abac)
Seen = 1 x ARRAY(0x182b3dc)
Seen = 1 x HASH(0x22aa74)
$VAR1 = [];
$VAR1 = [];
$VAR1 = {};