Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

checking if hashref value exists based on a dynamic array

by jonathan415 (Novice)
on Aug 08, 2008 at 06:12 UTC ( [id://703051]=perlquestion: print w/replies, xml ) Need Help??

jonathan415 has asked for the wisdom of the Perl Monks concerning the following question:

I have an hashref that has the following data.
$href = { 'a' => { 't' => { 'x' => { '2008-08-07' => 1 } } } 'b' => { 'd' => { 'o' => { '2008-08-06' => 1 } } } };

and I have an array with the following data:
@array = ('a', 't', 'x', '2008-08-07');
I know that I could see if $href->{a}->{t}->{x}->{2008-08-07} exists by just typing:

if (exists $href->{a}->{t}->{x}->{2008-08-07} ){ print "href value exists"; }
But that would be too statically hard encoded and manual.
I am trying to find a more elegant way to see if the hashref exists based on a dynamically generated @array values that aren't known yet.
That way I can generate the exists statement corresponding to whatever the array length and values are instead dynamically. Basically if the array turns out to be:
@array2 = ('b', 't', 'm', 'p');
I'd like to check if:
$href->{b}->{t}->{m}->{p}
exists without typing out "b, t, m, p".

Replies are listed 'Best First'.
Re: checking if hashref value exists based on a dynamic array
by Corion (Patriarch) on Aug 08, 2008 at 06:17 UTC
      ikegami, thanks for recommending Data::Diver. I did take a look at it, and it does answer the question. But the problem with modules is that they do the work, and you don't know how they done it. I was more interested in a ways of mapping data structure myself. My first question was actually very different from this one, and I was able to use the concepts of that answer to solve a more complex problem that I had. Basically, I was interested seeing ways of transversing the data structure and how those values relate to each other. If anyone has any other ways of doing it, I'm interested in seeing it.

        But the problem with modules is that they do the work, and you don't know how they done it.

        Probably something along the lines of the following, with error checking added.

        my $p = \$href; $p = \($$p->{$_}) for @keys; $$p = $val;

        Update: Oops, the above is code for setting with autovivification (your other question). Checking if the indexes exist without autovivification could be done using

        my $p = $href; for (@keys) { return 0 if !exists($p->{$_}); $p = $p->{$_}; } return 1;
        But the problem with modules is that they do the work, and you don't know how they done it.

        The source code is generally available, and many modern modules include decent test suites.

        Look inside and you'll know
Re: checking if hashref value exists based on a dynamic array
by pc88mxer (Vicar) on Aug 08, 2008 at 06:19 UTC
    sub deep_exists { my $hash = shift; return 0 if @_ == 0; while (@_ > 1) { $hash = $hash->{shift} or return 0; } return exists $hash->{$_[0]}; } if (deep_exists(\%hash, 'a', 't', 'etc')) { ... }

      Did you try this? Generally, "$hash->{shift}" is interpreted as "$hash->{'shift'}", but I think you mean "$hash->{shift()}".

      Also, this and other solutions I've seen here seem to ignore the possibility of running into a non-hash somewhere along the way.

      use Test::More 'tests' => 5; sub deep_exists { my $hash = shift; my $key = shift; return 0 if ( ref $hash ne ref {} || ! exists $hash->{$key} ); return deep_exists( $hash->{$key}, @_ ) if @_; return 1; } my %h; $h{there}{also}{yes} = 1; $h{hash}{shift}{scalar} = 1; ok( deep_exists( \%h, 'there', 'also', 'yes' ), 'there also yes' ); ok( deep_exists( \%h, 'there', 'also' ), 'there also' ); ok( ! deep_exists( \%h, 'there', 'also', 'no' ), 'there also no' ); ok( deep_exists( \%h, 'hash', 'shift', 'scalar' ), 'hash shift scalar' + ); ok( ! deep_exists( \%h, 'hash', 'shift', 'scalar', 'hash' ), 'hash shift scalar hash' );

        Also, this and other solutions I've seen here seem to ignore the possibility of running into a non-hash somewhere along the way

        Mine (Data::Diver) checks.

Re: checking if hashref value exists based on a dynamic array
by NetWallah (Canon) on Aug 08, 2008 at 06:32 UTC
    Extract/adapt from this code as needed:
    my %z=(aa=>{bb=>{cc=>44}});; sub chk{ my ($v,$h)=@_; return 1 unless @$h; return 0 unless exists $v->{my $x=shift @$h}; return chk($v->{$x},$h) } print qq[found\n] if chk(\%z,[qw(aa bb cc)]);
    Not the best naming convention - but this is a sample (and it's getting late ...) ...

         Have you been high today? I see the nuns are gay! My brother yelled to me...I love you inside Ed - Benny Lava, by Buffalax

Re: checking if hashref value exists based on a dynamic array
by localfilmmaker (Novice) on Aug 10, 2008 at 22:58 UTC
    One important thing to keep in mind while working with large complex data structure and checking for existence is that some hash entries will be created just by using them. For example,
    my %hash = ( a => { ab => { ac => 'yup', }, }, ); # Check for existence if (exists $hash{aa}->{ab}->{ac}) { ## Notice that 'aa' is a typo an doesn't exist ## but will be auto-created and now contain a ## hash ref with one entry 'ab'. print "ac exists.\n"; ## won't get printed } if (exists $hash{aa}) { ## This will succeed because $hash{aa} was auto ## created above. print "aa exists.\n"; ## will get printed }
    The exists check works on the last part of the data structure and not each step through the data structure. Meaning:
    if exists $hash{aa} ## exists doesn't check this ->{ab} ## Nor this ->{ac} ## Ah ha! exists does check here ;
    Everything before that last part of the data structure gets auto created if it doesn't exist. Only the last part will not. Just keep that in mind. -spencer

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://703051]
Approved by Corion
Front-paged by runrig
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others about the Monastery: (6)
As of 2024-04-23 15:22 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found