Safe way to remove elements from a list in Perl?
I'm having some weird results from this perl code - I need to delete several elements from a list of Association objects.
My approach is to scan the list once, push the matches to another array, then iterate that array and delete each one, but I haven't escaped the "don't delete while iterating pitfall".
Any ideas on how to avoid this? Many thanks.
my @agentConfAssociationDeletionsList = (
"AcceptTPCookie",
"AgentNamesAreFQHostNames",
"BadCssChars",
"LogLocalTime"
);
#find associations to remove
my @associationsToRemove = ()开发者_StackOverflow;
foreach my $association ($agentConf->GetAssociations()) {
if ( grep {$_ eq $association->Name()} @agentConfAssociationDeletionsList) {
print "pushing " . $association->Name() . "\n";
push(@associationsToRemove, $association);
}
}
#remove them
foreach my $association (@associationsToRemove) {
print "removing association: " . $association->Name();
agentConf->RemoveAssociation($association);
}
Your first loop is this:
my @associationsToRemove = ();
foreach my $association ($agentConf->GetAssociations()) {
if ( grep {$_ eq $association->Name()} @agentConfAssociationDeletionsList) {
print "pushing " . $association->Name() . "\n";
push(@associationsToRemove, $association);
}
}
which is equivalent to this:
my @associationsToRemove = ();
my @associations = $agentConf->GetAssociations();
foreach my $association (@associations) {
if ( grep {$_ eq $association->Name()} @agentConfAssociationDeletionsList) {
print "pushing " . $association->Name() . "\n";
push(@associationsToRemove, $association);
}
}
So, GetAssociations() is called before the first iteration of the
loop. There is no "don't delete while iterating pitfall" here, that
pitfall generally comes up insideeach
based loops and C-style for
loops. The problem is probably something inside the RemoveAssocition()
method.
Another possibility is that the $association
objects returned from
GetAssociations()
aren't fully copied when they're passed back: the
$association
objects could still be internal data from $agentConf
. This could be a hidden "don't delete while iterating" pitfall, hard to say without knowing the implementation of $agentConf
or even what its interface is.
Also, you're missing a sigil on agentConf
in your second loop but
that's probably just a typo.
What sort of "weird results" are you getting? The code you posted has no obvious problems in it (you aren't changing @associationsToRemove
while iterating over it, so "don't delete from a list you're iterating over" doesn't apply), so I'm inclined to suspect that the actual problem is in agentConf->RemoveAssociation
.
you can use hash approach like this,
my %h = map {$_ => 1 } @agentConfAssociationDeletionsList;
if (exists $h{$agentConfAssociationDeletionsList}) {
delete $h{$agentConfAssociationDeletionsList}; # like that
}
Make a copy of the original list, and iterate through the copy when deleting.
精彩评论