There are many references as to how to check if a hash is empty. I tried them all in the following script:
use strict;
use warnings;
use Data::Dumper;
$Data::Dumper::Sortkeys = 1;
# Signals come...
my %items = (
item_1 => {signal_1 => 'up',
signal_2 => 'down',
signal_3 => 'up',
},
item_2 => {signal_1 => 'down',
},
item_3 => {signal_1 => 'up',
signal_3 => 'down',
signal_4 => 'down',
signal_5 => 'down',
},
);
# ... and signals go:
delete $items{'item_2'}->{'signal_1'};
# and sometimes all signals are gone from an item:
print Dumper(\%items);
# in that case we would like the signal count to show 0 (zero).
my %signals;
foreach my $item (sort keys %items){
#$signals{$item} = 0;
foreach my $signal (sort keys %{$items{$item}}){
if (not %{$items{$item}}) {print "HERE\n"; $signals{$item} = 0}
elsif($items{$item}->{$signal} eq 'up') {$signals{$item}++}
elsif($items{$item}->{$signal} eq 'down'){$signals{$item}--}
}
}
# unfortunately the item disappears completely!
print Dumper(\%signals);
It seems the iterator skips over the empty hash completely. My only way to produce a correct result was to initiate each count to zero (commented out) and let it be incremented/decremented by non-empty hashes.
Why is it...???
If there are no keys in a hash then keys
returns an empty list ()
. When you iterate with foreach
over an empty list, the body of the loop will never be called. So your print "HERE"
will never be reached. This is correct.
foreach (()) {
print "foo";
}
__END__
(no output)
Perl's auto-vivification creates values in a hash for you when you use them the first time, and values start out as 0
when you do math on them. That's why you can add and substract from them in your loop inside the conditions.
To make it work, you've already done the right thing with your commented out line.
foreach my $signal (sort keys %{$items{$item}}){
$signals{$item} = 0;
if ( ...
Now you initialize every key to 0
first. That does the same doing it implicitly as described above, it just does it every time.