in reply to re-useing a hash

It looks like you want a lexical variable. Use my() to make the variable private to the block. With each iteration, you get a different hash (and at the end, throw the current on away).

foreach $uniqu ( ... ){ my %hash; ...

However, what you have now should be clearing out the hash. Setting it to the empty list shouldn't leave anything in it. There might be something else going on if you are seeing odd results.

Good luck!

brian d foy <>

Replies are listed 'Best First'.
Re^2: re-useing a hash
by ministry (Scribe) on Apr 20, 2005 at 18:17 UTC
    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.
      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.


      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 <>
      Did you follow step 2 of my advice?