2012-10-31 88 views
0

目标:从阵列删除数组元素完全

我写了一个脚本,删除特定的值,并将其工作正常,但我不开心我写它的方式。所以我很想知道是否有更好的方式来编写它。请考虑下面的使用案例:

我有一个嵌套的散列/散列/数组...像下面。我需要删除其中有他们的名字local任何数组值:

#!/usr/bin/perl -w 
use strict; 
use Data::Dumper; 

my $hash = { esx1 => 
        { cluster => "clu1", 
         fd  => "fd1", 
         ds  => [ 
             'ds1', 
             'ds2', 
             'localds', 
            ], 
        }, 
      esx2 => 
        { cluster => "clu2", 
         fd  => "fd2", 
         ds  => [ 
             'ds3', 
             'ds4', 
             'dslocal', 
            ], 
        }, 
      }; 


foreach my $a (keys %$hash) 
{ 
    foreach (0..$#{ $hash->{$a}->{ds} }) 
    { 
     delete $hash->{$a}->{ds}->[$_] if $hash->{$a}->{ds}->[$_] =~ /local/i; 
     @{ $hash->{$a}->{ds} } = grep defined, @{ $hash->{$a}->{ds} }; 
    } 
} 

print Dumper ($hash); 

所以脚本删除了“localds”和“dslocal”,并保持一切完好无损。

问题

  1. 是否有写foreach (0..$#{$hash->{$a}->{ds} })
  2. 如果我不写上面的grep线清洁器的方式,将得到的阵列具有含local删除的值,但由替换undef。这是为什么发生。

谢谢。

回答

2

为什么第一迭代通过数组和删除元素,然后寻找“未删除”节点(边注 - 这grep应该是外循环)?你可以从一开始就寻找好的节点!将整个循环替换为:

foreach my $a (keys %$hash) 
{ 
    @{ $hash->{$a}->{ds} } = grep { !/local/i } @{ $hash->{$a}->{ds} }; 
} 
+0

完美。非常感谢。这种方式更加简洁,易于理解。我从一开始就知道必须有一种更简单的方法来完成这项工作。就是这个。谢谢你的时间。 – slayedbylucifer

1

不是更整洁,但是:

foreach my $a (keys %$hash) 
{ 
    my $temp; 
    foreach (@{ $hash->{$a}->{ds} }) 
    { 
     push(@$temp, $_) unless $_ =~ /local/i; 
    } 
    $hash->{$a}->{ds} = $temp; 
} 

删除不改变阵列结构,它只是改变了数组的内容。由于在你的方法中,你需要grep定义的条目来创建一个你想要的结构的新数组,然后覆盖旧的数组。

编辑: 这是更好的上perldoc page for delete

删除()也可以在阵列和阵列片使用的说明,但其行为是那么简单。虽然exists()将为已删除的条目返回false,但删除数组元素永远不会更改现有值的索引;使用shift()或splice()。但是,如果所有删除的元素落在数组的末尾,则数组的大小缩小到仍然对exists()测试为true的最高元素的位置,如果没有,则将其值设为0。

编辑:

正如指出的暴徒剪接会做你想要什么:

foreach my $a (keys %$hash) 
{ 
    for(0..$#{ $hash->{$a}->{ds} }) 
    { 
     splice(@{ $hash->{$a}->{ds} }, $_, 1) if $hash->{$a}->{ds}->[ $_ ] =~ /local/i; 
    } 
} 
+2

'splice'是一个内建函数,它可以从列表中删除项目3并将所有较高的索引向下调整一个。 – mob

+0

谢谢,纠正了答案;我是一个不知道拼接的白痴...... – beresfordt

+0

我不能使用拼接,因为需要删除的元素的索引在我的散列中不是常量。我在我的代码中发布的是我正在尝试做的事情的模型。 – slayedbylucifer

0

你可以使用目录:: MoreUtils QW/first_idx /拿到/本地索引/像这样

first_idx { $_ =~ /local/i } @{$hash->{$a}->{ds}}; 

然后做你想做的。

5

delete是散列中的元素。它恰好适用于数组的实现,但不应该依赖它。

对于数组,您希望使用拼接。

splice @{ $ref->{to}->{array} }, $index, 1,(); 

这将替换起始于$index(),空列表1-元件子列表。

+0

我无法使用拼接,因为需要删除的元素的索引在我的散列中不是常量。我在我的代码中发布的是我正在尝试做的事情的模型。 – slayedbylucifer

+0

当然可以。您使用上述搜索来查找索引。 – LeoNerd

+0

我有多个与“本地”在其中的条目。我不确定拼接语法...现在使用Google搜索。 – slayedbylucifer

1
for my $h (values %$hash){ 
    $h->{ds} = [ grep { $_ !~ /local/i } @{$h->{ds}} ]; 
} 
+0

这与我接受的相似。但是这更加神秘,我想我将无法解释它在几周后所做的事情。我正在学习perl :)。希望我能接受2个答案。 – slayedbylucifer