目标:从数组中删除特定值
我已经写了一个脚本并且它工作正常,但我写的方式并不高兴。所以我很想知道是否有更好的方法来编写它。请考虑以下用例:
我有一个嵌套的哈希/哈希/数组......如下所示。我需要删除名称中包含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
”并保留其他所有内容。
问题:
foreach ( 0..$#{$hash->{$a}->{ds} } )
循环grep
行,则结果数组的值包含local
已删除但由undef
替换。为什么会这样呢。感谢。
答案 0 :(得分:5)
delete
用于散列中的元素。它恰好通过一个实现的怪癖在数组上工作,但不应该依赖它。
对于数组,您希望使用splice。
splice @{ $ref->{to}->{array} }, $index, 1, ();
这将替换从$index
开始的1元素子列表,其中()
为空列表。
答案 1 :(得分:2)
为什么首先遍历数组并删除元素,然后查找“未删除”节点(旁注 - 这个grep
应该在外部循环)?你可以从一开始就寻找好的节点!用以下代码替换整个循环:
foreach my $a ( keys %$hash )
{
@{ $hash->{$a}->{ds} } = grep { !/local/i } @{ $hash->{$a}->{ds} };
}
答案 2 :(得分:1)
不太整洁但是:
foreach my $a ( keys %$hash )
{
my $temp;
foreach ( @{ $hash->{$a}->{ds} } )
{
push(@$temp, $_) unless $_ =~ /local/i;
}
$hash->{$a}->{ds} = $temp;
}
删除不会改变数组结构,只会改变数组内容。因为在你的方法中你需要grep定义的条目来创建你想要的结构的新数组,然后覆盖旧的数组。
上可以更好地解释这一点delete()也可用于数组和数组切片,但其行为不那么简单。虽然exists()将为已删除的条目返回false,但删除数组元素永远不会更改现有值的索引;使用shift()或splice()。但是,如果所有已删除的元素都落在数组的末尾,则数组的大小会缩小到仍然为exists()测试为true的最高元素的位置,如果没有,则为0。
编辑:
正如mob splice所指出的,你会做你想做的事情:
foreach my $a ( keys %$hash )
{
for(0..$#{ $hash->{$a}->{ds} } )
{
splice( @{ $hash->{$a}->{ds} }, $_, 1 ) if $hash->{$a}->{ds}->[ $_ ] =~ /local/i;
}
}
答案 3 :(得分:1)
for my $h (values %$hash){
$h->{ds} = [ grep { $_ !~ /local/i } @{$h->{ds}} ];
}
答案 4 :(得分:0)
您可以使用List :: MoreUtils qw / first_idx /来获取/ local / like索引
first_idx { $_ =~ /local/i } @{$hash->{$a}->{ds}};
然后用你做你想做的事。