diff options
author | brian d foy <brian.d.foy@gmail.com> | 2010-09-14 12:16:49 -0500 |
---|---|---|
committer | brian d foy <brian.d.foy@gmail.com> | 2010-09-14 12:19:03 -0500 |
commit | a1bbdff363ce08fa98da9f4043f11f13488da5b2 (patch) | |
tree | 1f3eaec37b49e643b03aa5d98d269f97d37995e5 /pod/perlfaq4.pod | |
parent | 03c6e0f89140dee7d6b58e7370bc8e0f2bfaf3da (diff) | |
download | perl-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.pod | 68 |
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? |