Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.
 
PerlMonks  

Re^2: re-useing a hash

by ministry (Scribe)
on Apr 20, 2005 at 18:17 UTC ( [id://449707]=note: print w/replies, xml ) Need Help??


in reply to Re: re-useing a hash
in thread re-useing a hash

thanks for the info brian_d_foy. however after taking your advice and making my scalar a lexical i am still unable to re-use my hash each time loop through my foreach $uniqu ... statement. i also took the advice given by isotope and Scarborough and made my counter look like $hash{$rule}++ and also tried to use the  undef %hash; at the end of my loop, but still with no luck. here is what my loop looks like now:
foreach $uniqu (@uniqu){ my %hash; ...(process each key/value)... undef %hash; }
it still seems as though every time i go through my foreach loop, the clearing of my %hash is not taking place. any other suggestions?

Good judgement comes with experience. Unfortunately, the experience usually comes from bad judgement.

Replies are listed 'Best First'.
Re^3: re-useing a hash
by 5mi11er (Deacon) on Apr 20, 2005 at 19:39 UTC
    Then me thinks you have some other bug making you think the hash isn't empty. Actually blindly following the advice given so far has caused some additional problems, namely scoping issues.

    Lets examine a quick example:

    #!/usr/bin/perl use strict; use warnings; use vars qw(%hash); sub foo { $hash{$_[0]}+=3; } sub bar { $hash{$_[0]}++; foo($_[0]); } foreach my $i (0..10) { my %hash; $hash{$i} = $i*3; bar($i); foo($i); foreach my $j (sort keys %hash) { print "hash{$j} = $hash{$j}\n"; } } print "done\n"; foreach my $j (sort keys %hash) { print "hash{$j} = $hash{$j}\n"; }
    Ok, it looks a bit convoluted, definitely contrived, but hey it's just an example. Running through the program through our brains, we're creating a hash with a key of 0 to 10, and setting its value to 3*x, then calling bar() using that index. Bar increments that hash element x by one, then calls foo() which adds 3 more so the value of %hash{0} at this point should be 4. Then we call foo() again, so we're up to 7. %hash{1} should similarly get a value of 3+1+3+3=10 etc.

    Oh, and each time through we should end up with a new empty hash too, so if we see repeaters, then the hash is sticking around

    Run the code and we get this output:

    hash{0} = 0 hash{1} = 3 hash{2} = 6 hash{3} = 9 hash{4} = 12 hash{5} = 15 hash{6} = 18 hash{7} = 21 hash{8} = 24 hash{9} = 27 hash{10} = 30 done hash{0} = 7 hash{1} = 7 hash{10} = 7 hash{2} = 7 hash{3} = 7 hash{4} = 7 hash{5} = 7 hash{6} = 7 hash{7} = 7 hash{8} = 7 hash{9} = 7
    Well that wasn't what we expected was it. We don't have any repeaters, so we are getting a new hash, but the values aren't correct. And why do we have a %hash with values in it to print at the end?

    Scoping is causing issues for you. Neither foo() nor bar() know anything about the private %hash we created by the "my %hash;" line within the foreach loop. bar() is creating a new global version of that hash and hash entry when you call it, and foo() is likewise acting on that new global version of %hash. That is why the initially printed values are only multiplied by three and the remaining global %hash all have values of 7 once you're out of the foreach loop .

    So, how do you fix the problem? Either don't use "my %hash;", and continue to use a global %hash variable (not really recommended, but it works) or start passing a reference to the hash to the subroutines that need to access it. If you don't use "my %hash", then the "undef %hash;" line will be needed at the end of your foreach loop.

    Update: You can't use a "my %hash" in this case, as you can't take a reference to a my variable (at least I'm pretty sure you can't) since it doesn't exist on the glob table like a normal variable does. Just add the "undef %hash;" at the end of the foreach loop and it should start working more correctly than it currently does.

    -Scott

    Update: Fixed various typo's... Update 2: Made the explaination a bit more clear, and fixed the "reference" idea

      Can't take a reference to a lexical variable? Surely you jest. What happened when you tried it?

      He wants a lexical variable because he wants a new hash at the start of each iteration of the loop. Pass that hash as a reference to the gather function (or better yet, just get the hash by having gather() return a reference).

      Global variables are bad news, and that's why this thread exists. :)

      --
      brian d foy <brian@stonehenge.com>
Re^3: re-useing a hash
by isotope (Deacon) on Apr 21, 2005 at 15:46 UTC
    Did you follow step 2 of my advice?


    --isotope

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://449707]
help
Chatterbox?
and the web crawler heard nothing...

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

    No recent polls found