【问题标题】:Safe way to remove elements from a list in Perl?从 Perl 列表中删除元素的安全方法?
【发布时间】:2010-11-01 22:26:41
【问题描述】:

我从这个 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);
}

【问题讨论】:

    标签: perl


    【解决方案1】:

    你的第一个循环是这样的:

    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 上的印记,但是 这可能只是一个错字。

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        【解决方案3】:

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

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

        【讨论】:

        • 使用哈希比 grepping 数组更有效,但是您的 if ... delete 并没有做任何与他的原始代码类似的事情。
        【解决方案4】:

        复制原始列表,删除时遍历副本。

        【讨论】:

        • -1:这就是他已经在做的事情:制作第二个列表,其中包含要删除的原始列表中的项目,然后遍历副本。
        猜你喜欢
        • 2021-09-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-11-25
        相关资源
        最近更新 更多