从Perl中的列表中删除元素的安全方法?

时间:2010-11-01 06:04:45

标签: perl

我从这个perl代码中得到了一些奇怪的结果 - 我需要从Association对象列表中删除几个元素。

我的方法是扫描列表一次,将匹配推送到另一个数组,然后迭代该数组并删除每个数组,但我没有逃脱“迭代陷阱时不要删除”。

有关如何避免这种情况的任何想法?非常感谢。

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);
}

4 个答案:

答案 0 :(得分:3)

你的第一个循环是:

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

相当于:

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

因此,在第一次迭代之前调用GetAssociations() 环。这里没有“在迭代陷阱时不删除” 陷阱通常出现在基于each的循环内部和C风格for 循环。问题可能在RemoveAssocition()内部 方法

另一种可能性是从$association对象返回 当GetAssociations()被传回时,$association没有被完全复制 $agentConf个对象仍然可以是$agentConf的内部数据。这可能是一个隐藏的“不要在迭代时删除”的陷阱,很难说不知道agentConf的实现甚至是它的接口是什么。

另外,你在第二个循环中错过{{1}}上的印记但是 这可能只是一个错字。

答案 1 :(得分:2)

你得到什么样的“奇怪结果”?你发布的代码没有明显的问题(你在迭代它时没有改变@associationsToRemove,所以“不要从你正在迭代的列表中删除”不适用),所以我'我倾向于怀疑实际问题在agentConf->RemoveAssociation

答案 2 :(得分:1)

你可以使用像这样的哈希方法,

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

答案 3 :(得分:0)

制作原始列表的副本,并在删除时迭代副本。