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');
% ./tst.pl
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 :)
|