None of the answers you have seen so far consider the possibility that the hash values may be anything other than simple strings or numbers.
While that may be appropriate to your data, it isn't a safe assumption in general.
This example modifies the hash in place, removing only empty string values and preserving everything else.
Note that, even though it may need to be installed, Data::Dump is usually a better choice than Data::Dumper, as shown here.
use strict;
use warnings;
my @alpha = ('a' .. 'm');
my $hash = {
a => ['1', '2', '', '5', '6', '7', '8'],
b => ['1', '2', '3', '6', '7', '8', '9'],
c => ['2', '', '4', '', '', '8', ''],
d => ['5', '', '6', '', undef, '22', '', 'aa', -51.2, \@alpha],
};
for my $list (values %$hash) {
for (my $i = $#{$list}; $i >= 0; --$i) {
my $item = $list->[$i];
splice(@{$list}, $i, 1) if defined $item and $item eq '';
}
}
use Data::Dump;
dd $hash;
output
{
a => [1, 2, 5 .. 8],
b => [1, 2, 3, 6 .. 9],
c => [2, 4, 8],
d => [5, 6, undef, 22, "aa", -51.2, ["a" .. "m"]],
}