summaryrefslogtreecommitdiff
path: root/pod/perlfaq4.pod
diff options
context:
space:
mode:
authorbrian d foy <brian.d.foy@gmail.com>2010-09-14 12:16:49 -0500
committerbrian d foy <brian.d.foy@gmail.com>2010-09-14 12:19:03 -0500
commita1bbdff363ce08fa98da9f4043f11f13488da5b2 (patch)
tree1f3eaec37b49e643b03aa5d98d269f97d37995e5 /pod/perlfaq4.pod
parent03c6e0f89140dee7d6b58e7370bc8e0f2bfaf3da (diff)
downloadperl-a1bbdff363ce08fa98da9f4043f11f13488da5b2.tar.gz
* Add multilevel hash exists() to perlfaq4
How can I check if a keys exists in a multilevel hash? How is it we got this far without ever answering this FAQ? :)
Diffstat (limited to 'pod/perlfaq4.pod')
-rw-r--r--pod/perlfaq4.pod68
1 files changed, 68 insertions, 0 deletions
diff --git a/pod/perlfaq4.pod b/pod/perlfaq4.pod
index de66738fd7..94fc873887 100644
--- a/pod/perlfaq4.pod
+++ b/pod/perlfaq4.pod
@@ -2421,6 +2421,74 @@ If you actually need to be able to get a real reference back from
each hash entry, you can use the Tie::RefHash module, which does the
required work for you.
+=head2 How can I check if a keys exists in a multilevel hash?
+
+(contributed by brian d foy)
+
+The trick to this problem is avoiding accidental autovivification. If
+you want to check three keys deep, you might naïvely try this:
+
+ my %hash;
+ if( exists $hash{key1}{key2}{key3} ) {
+ ...;
+ }
+
+Even though you started with a completely empty hash, after that call to
+C<exists> you've created the structure you needed to check for C<key3>:
+
+ %hash = (
+ 'key1' => {
+ 'key2' => {}
+ }
+ );
+
+That's autovivification. You can get around this in a few ways. The
+easiest way is to just turn it off. The lexical C<autovivification>
+pragma is available on CPAN. Now you don't add to the hash:
+
+ {
+ no autovivification;
+ my %hash;
+ if( exists $hash{key1}{key2}{key3} ) {
+ ...;
+ }
+ }
+
+The C<Data::Diver> module on CPAN can do it for you too. Its C<Dive>
+subroutine can tell you not only if the keys exist but also get the
+value:
+
+ use Data::Diver qw(Dive);
+
+ my @exists = Dive( \%hash, qw(key1 key2 key3) );
+ if( ! @exists ) {
+ ...; # keys do not exist
+ }
+ elsif( ! defined $exists[0] ) {
+ ...; # keys exist but value is undef
+ }
+
+You can easily do this yourself too by checking each level of the hash
+before you move onto the next level. This is essentially what
+C<Data::Diver> does for you:
+
+ if( check_hash( \%hash, qw(key1 key2 key3) ) ) {
+ ...;
+ }
+
+ sub check_hash {
+ my( $hash, @keys ) = @_;
+
+ return unless @keys;
+
+ foreach my $key ( @keys ) {
+ return unless eval { exists $hash->{$key} };
+ $hash = $hash->{$key};
+ }
+
+ return 1;
+ }
+
=head1 Data: Misc
=head2 How do I handle binary data correctly?