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

My issue is that the perl script (as I have done it so far) created empty branches when I try to check some branches on existence.

I am using multydimentional hashes: found it as the best way for information that I need to handle. Saing multidimentional I means hash of hashes ... So, I have

$hsh{k1}{k2}{k3}{k4}=v1; $hsh{k1}{k9}{k3}{k33}=v2; ....

In some point I need to check some 'set of keys' on existence in the hash. So, I check:

if ( $hsh{ch1}{ch2}{ch3} ) { ...something... }

And, suddenly I've realized, that such check creates the intermediate branches to access the final one for checking!

So, if there is no $hsh{ch1} before the check, it will be created to access the key 'ch2', which will be created to access the 'ch3'

QUESTION: Is there a way to avoid such aromatic creation ????

Logically, I would expect the Perl to get FALSE as soon as any key is not exist in the hash, but it is not happening!

Sure I could do:

if ( $hsh{ch1} && $hsh{ch1}{ch2} && $hsh{ch1}{ch2}{ch3} ) {...}

but it is so annoying, especially when I have many hashes with 7- 10 keys!

I have creates some function to check a hash 'reasonably', sending hash reference and array of keys to be checked, and it works fine, but it is slows down the processing visibly.

Here is an example of what I am talking about:

DB<4> $h{a}{b}=[1,2]; $h{a}{c}=[3,4] #hash with two elements (array +s) and in 2 levels DB<5> use Data::Dumper #good way to display DB<6> p Dumper\($a,%h) $VAR1 = \undef; $VAR2 = { 'a' => { 'c' => [ 3, 4 ], 'b' => [ 1, 2 ] } }; DB<7> p 'da' if !$h{p}{m} #checking for an existent keys and elemen +t da DB<8> p Dumper\($a,%h) $VAR1 = \undef; $VAR2 = { 'p' => {}, # <<== created one !!! 'a' => { 'c' => [ 3, 4 ], 'b' => [ 1, 2 ] } }; DB<9> delete $h{p}

Once again: Is there a way to avoid such behavior without creating additional function?

Thanks!

Replies are listed 'Best First'.
Re: perl: restrict perl from automaticaly creating a hash branches on check
by dasgar (Priest) on Nov 06, 2014 at 17:16 UTC
      Exactly!! Thanks! I Go to read!
Re: perl: restrict perl from automaticaly creating a hash branches on check
by Laurent_R (Canon) on Nov 06, 2014 at 19:02 UTC
    This is cross posted on The Perl Guru forum (http://perlguru.com/gforum.cgi?post=80149;sb=post_latest_reply;so=ASC;forum_view=forum_view_collapsed;;page=unread#unread) and apparently also on SO. It is considered polite to inform the reader about cross-posts to avoid duplicate work at various places of the Internet.

    I have provided two answers on the Perl Guru. Just to repeat here: the autovivification module or the hard manual way, quickly demonstrated here under the Perl debugger:

    DB<1> $h{a}{b}{c} = 2; DB<2> print "foo" if defined $h{d}{e}{f} ; DB<3> print "foo" if $h{g} && $h{g}{h} && $h{g}{h}{i}; DB<4> x \%h; 0 HASH(0x600500b60) 'a' => HASH(0x600509d30) 'b' => HASH(0x600500a88) 'c' => 2 'd' => HASH(0x600500c38) 'e' => HASH(0x600500980) empty hash DB<5>
    Line 1 (DB<1>) is just creating the hash, to make sure it exists.

    Line 2 is checking for the definedness of a deeply nested element of the hash.

    Line 3 is doing the same thing, but level by level. If the first conditional expression is false, the others will not be evaluated because they are short-circuited (the whole expression cannot be right if the first one is wrong (undefined).

    Line 4 prints out the structure of the hash. You can see that line 2 created all the level below the last one (autovivification of levels 1 and 2), where as line 3 did not produce any autovivification (did not create subentries for the lower levels).

    Update: corrected the case of the initial letter of the autovification module, which is lc, no uc as I originally wrote. Thanks to AnomalousMonk for the correction and for providing a link.

    In addition, please note that the tests described in the debugger session above are really a quick example and that they might fail if the value in the most deeply nested value may be an end value rather than a reference to another sub-hash, in which case the test might return false despite the value being defined, if that value is itself false (for example 0 or the empty string). So that, depending on what the exact purpose of the test really is, it might sometimes be better or more reliable to rewrite line DB<3> above as:

    print "foo" if $h{g} && $h{g}{h} && exists $h{g}{h}{i};
    or possibly:
    print "foo" if $h{g} && $h{g}{h} && defined $h{g}{h}{i};
    The best solution between the three solutions really depends on what exactly you are trying to know and what the data structure really is (if you are guaranteed that the third nesting level cannot be an end value, but can only be a reference or not exist, then you don't need to worry about that, as a defined reference is always going to evaluate to true). All this to say that this was just an example, you'll need to adapt the syntax to the real scenario.

    Also corrected a silly mistake in the initial DB<3> line.

      You right, I did cross-posted: did not know wich forum has any activities.

      Will responce on that, perlguru forum

        The general consensus is that there is nothing wrong with cross-posting, but please just inform the readers on the various forums where you do that to prevent that people spend time trying to find a solution to something thazt has already been solved on the other end of the Internet.

      Thanks for answers and corrections.

      I am responding to this and other posts on Perl-Guru-Forum: The same topic

A reply falls below the community's threshold of quality. You may see it by logging in.