Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw
 
PerlMonks  

RESOLVED - Autovivification: How Did I End Up With a Larger Number of Hash Keys Here?

by perldigious (Priest)
on Mar 03, 2020 at 17:59 UTC ( [id://11113721]=perlquestion: print w/replies, xml ) Need Help??

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

Okay, this just has to be my brain missing something, and it's driving me crazy.

All the following code should be doing is deleting hash keys, not adding them, yes?

print scalar(keys %auto_picks), "\n"; while (my $line = <$sub_fh>) { my @data = split /\t/, $line; if (exists $auto_picks{$data[0]}{$data[1]}) { $auto_picks{$data[0]}{$data[1]} -= $data[2]; if ($auto_picks{$data[0]}{$data[1]} <= 0) { delete $auto_picks{$data[0]}{$data[1]}; if (!keys %{$auto_picks{$data[0]}}) { delete $auto_picks{$data[0]}; } } } } print scalar(keys %auto_picks), "\n";

And yet, based on my data set the first print scalar(keys %auto_picks) returns a little over 100k, and the second more than twice that. Fellow Monks, I implore you, what is the cause of my stupid here?

----------

RESOLVED: Autovivification was my problem and turning it off via the autovivification module was my solution. Thanks to those that pointed out this was my problem.

Just another Perl hooker - My clients appreciate that I keep my code clean but my comments dirty.

Replies are listed 'Best First'.
Re: How Do I End Up With a Larger Number of Hash Keys Here?
by 1nickt (Canon) on Mar 03, 2020 at 18:20 UTC

    Hi, I would think that if (exists $auto_picks{$data[0]}{$data[1]}) has the potential to autovivify keys that did not exist. autovivification ...

    Hope this helps!


    The way forward always starts with a minimal test.

      Helps a lot, that's the problem I'm having.

      https://perlmaven.com/autovivification

      Also, good God, why?

      I'd be more inclined to call that a bug than a feature, especially in the exists/delete context I'm doing above.

      I'm both amazed I haven't run in to this prior, and terrified that maybe I have in past code I've written and I just never realized it. :-o

      Just another Perl hooker - My clients appreciate that I keep my code clean but my comments dirty.
        Its probably to late, but I do want to point out that your original code would work as intended (and perhaps even be clearer) if you test the levels separately. The "short circuit" feature of the "and" operator prevents the troublesome low-level test from running unless the upper-level key exists.
        if ( exists $auto_picks{ $data[0] } and exists $auto_picks{ $data[0] }{ $data[1] } ) {
        Bill

      Uh .. no.

      tab@music4:~ $ perl -de 1 Loading DB routines from perl5db.pl version 1.51 Editor support available. Enter h or 'h h' for help, or 'man perldebug' for more help. main::(-e:1): 1 DB<1> %hash = (); DB<2> use Data::Dumper; DB<3> print Dumper(\%hash) $VAR1 = {}; DB<4> if ( exists $hash{nothing} ) { print "Wow.\n"; } DB<5> !3 print Dumper(\%hash) $VAR1 = {}; DB<6>
      For me, the whole point of using exists is to avoid doing autovivification.

      But the example used a two level hash .. so I answered the wrong question. Ugh.

      Alex / talexb / Toronto

      Thanks PJ. We owe you so much. Groklaw -- RIP -- 2003 to 2013.

        Uh .. no.

        Actually, yes. 1nickt had a HoH, not just a simple hash. Intervening levels can and do get created, even when called by exists

        > perl -de 1 Loading DB routines from perl5db.pl version 1.27 Editor support available. Enter h or `h h' for help, or `man perldebug' for more help. main::(-e:1): 1 DB<1> %hoh = (); DB<2> use Data::Dumper; DB<3> print Dumper(\%hoh) $VAR1 = {}; DB<4> if (exists($hoh{nothing}{second})) { print "wow.\n"; } DB<5> !3 print Dumper(\%hoh) $VAR1 = { 'nothing' => {} };
Re: How Do I End Up With a Larger Number of Hash Keys Here?
by BillKSmith (Monsignor) on Mar 03, 2020 at 19:25 UTC
    Refer: exists.
    Although the most deeply nested array or hash element will not spring into existence just because its existence was tested, any intervening ones will.
    Bill

      Yes, exactly what's happening since I'm inside a 2D hash, thank you.

      Just another Perl hooker - My clients appreciate that I keep my code clean but my comments dirty.
Re: RESOLVED - Autovivification: How Did I End Up With a Larger Number of Hash Keys Here?
by AnomalousMonk (Archbishop) on Mar 04, 2020 at 09:00 UTC
Re: How Do I End Up With a Larger Number of Hash Keys Here?
by talexb (Chancellor) on Mar 03, 2020 at 19:27 UTC

    Update: Yes, there's something going on here -- my example below has to do with a one-level hash, whereas the original is about a two-level hash. Nothing to see here. This is not the Perl code you're looking for. You can go about your business.

    There must be something else going on here. Here's a simpler example that shows that I end up with fewer keys than I started with -- using just a one-dimensional hash. Code:

    #!/usr/bin/perl use warnings; use strict; use Data::Dumper; { my %hash = ( 1 => 5, 3 => 12, 7 => 19, 9 => 44 ); print 'At ' . __LINE__ . ' there are ' . ( scalar keys %hash ) . " keys: "; print Dumper(\%hash); my %hash2 = ( 1 => 5, 9 => 22 ); print "This should delete one of the keys, using this hash ..\ +n"; print Dumper ( \%hash2 ); foreach my $key ( keys %hash2 ) { if ( exists $hash{ $key } ) { $hash{ $key } -= $hash2{ $key }; if ( $hash{ $key } <= 0 ) { delete $hash{ $key }; } } } print 'At ' . __LINE__ . ' there are ' . ( scalar keys %hash ) . " keys: "; print Dumper(\%hash); }
    .. and the result:
    tab@music4:~/Pianoforte/Development/Perlmonks/11113721 $ perl hashkeys +.pl At 11 there are 4 keys: $VAR1 = { '9' => 44, '1' => 5, '3' => 12, '7' => 19 }; This should delete one of the keys, using this hash .. $VAR1 = { '1' => 5, '9' => 22 }; At 33 there are 3 keys: $VAR1 = { '9' => 22, '3' => 12, '7' => 19 }; tab@music4:~/Pianoforte/Development/Perlmonks/11113721 $
    I set the example up so that one of the keys would end up with zero (and get deleted), and another would be reduced, but not to zero. I started up with four keys, and finished with three.

    Check your code -- I'm guessing you're missing something.

    Alex / talexb / Toronto

    Thanks PJ. We owe you so much. Groklaw -- RIP -- 2003 to 2013.

Re: How Do I End Up With a Larger Number of Hash Keys Here?
by Anonymous Monk on Mar 03, 2020 at 18:26 UTC

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others rifling through the Monastery: (3)
As of 2024-03-29 01:49 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found