in reply to Scoping problems with recursive function

Now, on a broader note.

Your %dependencies hash is a list, by key, of the keys that key depends on. This is inconvenient for what you're trying to do, which is why you're jumping through some hoops.

To put the function in english:

foreach key foreach dependency of that key if this dependency is the one I want to delete, delete this key continue looping continue looping

Now, note that in the middle, if you decide to delete this key, you're still continuing to loop over its dependencies. So you'd really want to break out of there.

But better, you can avoid that loop completely, and just ask the question "am I ($key) one of the elements in this array?" with grep:

if( grep { $_ eq $key } @{$dependencies{$key}} ) { print "Going to call sub for $key\n"; mydel($key); }

That saves you writing the loop.

But, let's step back. The key you're deleting probably isn't a dependency for most of the keys in the hash. If you're going to be calling this a lot, it can be a little annoying spending all that time searching over lists you're not in. You're having to do that because your list shows the dependencies of each key.

But it would be even more convenient if instead it showed the keys that depend on each key. Then you could just loop over that list, deleting stuff. And it's pretty each to build that list from the one you have. Something like:

my %requiredby; for my $key (keys $dependencies) { for my $dep (@{$dependencies{$key}}) { push @{$requiredby{$dep}}, $key; } } # Or alternately, using a statement modifier to be shorter my %requiredby; for my $key (keys %dependencies) { push @{$requiredby{$_}}, $key for @{$dependencies{$key}}; }

Now you've got a lookup you can just loop directly over, and you can get even shorter. Obviously it costs some time and memory to build that %requiredby list, but if you're going to call the delete often, it's worth it. New version (tested):

#!/usr/bin/env perl5 use strict; use warnings; my %hash = ( 'one' => 1, 'two' => 2, 'three' => 3, 'four' => 4, 'five' + => 5); my %dependencies = ( 'one' => [], 'two' => [], 'three' => ['four'], 'four' => ['one','two'], 'five' => ['three'] ); my %requiredby; for my $key (keys %dependencies) { push @{$requiredby{$_}}, $key for @{$dependencies{$key}}; } sub my_del { my $thiskey = shift; # Find all the keys that depend on us, and so have to go for my $del ( @{$requiredby{$thiskey}} ) { # Recurse and delete one key that requires us print "Going to call sub for $del\n"; my_del($del); } # And finally get rid of us delete $hash{$thiskey}; print "Deleting $thiskey\n"; } my_del('one');
% ./ Going to call sub for four Going to call sub for three Going to call sub for five Deleting five Deleting three Deleting four Deleting one

Of course, won't catch infinite loops, like if we set four to depend on three as well. That's left as an exercise for the reader :)

Replies are listed 'Best First'.
Re^2: Scoping problems with recursive function
by Xiong (Hermit) on Mar 20, 2010 at 16:41 UTC

    I have no comment on the substantive issue but I would like to note that fullermd's reply goes much deeper than the others. I'd like to see more upvotes for it.

    The OP is a classic example of "How do I do this clumsy thing?" (I mean no disrespect to morrin by saying this. I often attempt clumsy things.) "Here's how to do that clumsy thing" is a good reply; "Here's a less clumsy approach" is much better.