Recipe 5.2 Testing for the Presence of a Key in a Hash
5.2.1 Problem
You need to know whether a hash has a
particular key, regardless of whatever value may be associated with
that key.
5.2.2 Solution
Use the exists
function.
# does %HASH have a value for $KEY ?
if (exists($HASH{$KEY})) {
# it exists
} else {
# it doesn't
}
5.2.3 Discussion
This code uses exists to check whether a key is in
the %food_color hash:
# %food_color per the introduction
foreach $name ("Banana", "Martini") {
if (exists $food_color{$name}) {
print "$name is a food.\n";
} else {
print "$name is a drink.\n";
}
}
Banana is a food.
Martini is a drink.
The exists function tests whether a key is
in the hash. It doesn't test whether the value
corresponding to that key is defined, nor whether the value is true
or false. We may be splitting hairs, but problems caused by confusing
existence, definedness, and truth can multiply like rabbits. Take
this code:
%age = ( );
$age{"Toddler"} = 3;
$age{"Unborn"} = 0;
$age{"Phantasm"} = undef;
foreach $thing ("Toddler", "Unborn", "Phantasm", "Relic") {
print "$thing: ";
print "Exists " if exists $age{$thing};
print "Defined " if defined $age{$thing};
print "True " if $age{$thing};
print "\n";
}
Toddler: Exists Defined True
Unborn: Exists Defined
Phantasm: Exists
Relic:
$age{"Toddler"} passes the existence, definedness,
and truth tests. It exists because we gave
"Toddler" a value in the hash; it's defined
because that value isn't undef; and it's true
because the value isn't one of Perl's false values.
$age{"Unborn"} passes only the existence and
definedness tests. It exists because we gave
"Unborn" a value in the hash, and it's defined
because that value isn't undef. It isn't
true, however, because 0 is
one of Perl's false values.
$age{"Phantasm"} passes only the existence test.
It exists because we gave "Phantasm" a value in
the hash. But because that value was undef, it
doesn't pass the definedness test. Because undef
is also one of Perl's false values, it doesn't pass the truth test
either.
$age{"Relic"} passes none of the tests. We didn't
put a value for "Relic" into the hash, so the
existence test fails. Because we didn't put a value in,
$age{"Relic"} is undef whenever
we try to access it. We know from "Phantasm" that
undef fails the definedness and truth tests.
Sometimes it's useful to store undef in a hash.
This indicates "I've seen this key, but it didn't have a meaningful
value associated with it." Take, for instance, a program to look up
file sizes given a list of files as input. This version tries to skip
files we've seen before, but it doesn't skip zero-length files, and
it doesn't skip files that we've seen before but don't exist.
%size = ( );
while (<>) {
chomp;
next if $size{$_}; # WRONG attempt to skip
$size{$_} = -s $_;
}
If we change the incorrect line to call exists, we
also skip files that couldn't be statted, instead
of repeatedly trying (and failing) to look them up:
next if exists $size{$_};
5.2.4 See Also
The exists and defined
functions in perlfunc(1) and Chapter 29 of
Programming Perl; the discussion of truth in
the "Scalar Values" section of perldata(1), and
the "Boolean Context" section of Chapter 2 of Programming
Perl
|