2010-11-01 8 views
0

J'ai des résultats bizarres avec ce code perl - j'ai besoin de supprimer plusieurs éléments d'une liste d'objets Association.Manière sûre de supprimer des éléments d'une liste dans Perl?

Mon approche consiste à balayer la liste une fois, pousser les correspondances à un autre tableau, puis itérer ce tableau et supprimer chacune d'entre elles, mais je n'ai pas échappé au "ne pas supprimer pendant l'itération".

Des idées pour éviter cela? Merci beaucoup.

my @agentConfAssociationDeletionsList = (
    "AcceptTPCookie", 
    "AgentNamesAreFQHostNames", 
    "BadCssChars", 
    "LogLocalTime" 
); 

#find associations to remove 
my @associationsToRemove =(); 
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); 
} 

Répondre

3

Votre première boucle est la suivante:

my @associationsToRemove =(); 
foreach my $association ($agentConf->GetAssociations()) { 
    if (grep {$_ eq $association->Name()} @agentConfAssociationDeletionsList) { 
     print "pushing " . $association->Name() . "\n"; 
     push(@associationsToRemove, $association); 
    } 
} 

qui équivaut à ceci:

my @associationsToRemove =(); 
my @associations = $agentConf->GetAssociations(); 
foreach my $association (@associations) { 
    if (grep {$_ eq $association->Name()} @agentConfAssociationDeletionsList) { 
     print "pushing " . $association->Name() . "\n"; 
     push(@associationsToRemove, $association); 
    } 
} 

Ainsi, GetAssociations() est appelée avant la première itération de la boucle . Il n'y a pas de "ne pas supprimer lors de l'itération du piège" ici, que l'écueil apparaît généralement à l'intérieur des boucles basées each et des boucles forfor . Le problème est probablement quelque chose à l'intérieur de la méthode RemoveAssocition() .

Une autre possibilité est que les objets $association retour de GetAssociations() ne sont pas entièrement copiés quand ils sont répercutés: les objets $association pourraient encore être données internes de $agentConf. Cela pourrait être un piège caché "ne pas supprimer en itérant", difficile à dire sans connaître l'implémentation de $agentConf ou même quelle est son interface.

De plus, il vous manque un sigil sur agentConf dans votre deuxième boucle mais c'est probablement juste une faute de frappe.

0

Effectuez une copie de la liste d'origine et parcourez la copie lors de la suppression.

+0

-1: C'est ce qu'il fait déjà: créer une deuxième liste contenant les éléments de la liste d'origine à supprimer, puis itérer sur la copie. –

1

vous pouvez utiliser une méthode de hachage comme celui-ci,

my %h = map {$_ => 1 } @agentConfAssociationDeletionsList; 
if (exists $h{$agentConfAssociationDeletionsList}) { 
    delete $h{$agentConfAssociationDeletionsList}; # like that 
} 
+0

L'utilisation d'un hachage est plus efficace que le remplissage d'un tableau, mais votre 'if ... delete' ne fait rien de similaire à son code d'origine. – cjm

2

Quel genre de « résultats étranges » êtes-vous? Le code que vous avez publié n'a pas de problèmes évidents (vous ne modifiez pas @associationsToRemove en l'itérant, donc "ne pas supprimer d'une liste que vous itérez" ne s'applique pas), donc je suis enclin à suspecter que le problème réel est dans agentConf->RemoveAssociation.

Questions connexes