我想用子程序从几个大数组中删除元素。我使用引用来避免副本进入子。
@a=qw(ok now what is hi the matter);
sub zonk {
$array=shift; # this is a reference of an array
foreach $i (0..$#$array) { # I saw some say to avoid last element to get size
#if (@$array[$i] =~ /hi/) { delete @$array[$i]; }
#if ($array->[$i] =~ /hi/) { delete $array->[$i]; }
#if ($array->[$i] =~ /hi/) { delete @$array->[$i]; }
if ($array->[$i] =~ /hi/) { print "FOUND "; }
print $array->[$i],"\n";
}
@$array = grep{$_} @$array; # removes empty elements
}
zonk(\@a);
print join(':',@a);
如果我按原样运行上面的程序:
ok
now
what
is
FOUND hi
the
matter
ok:now:what:is:hi:the:matter
但是,如果我使用任何注释行,我会得到:
delete参数不是hi.pl第10行的HASH元素或切片。
我最初尝试过拼接,但随后索引正在转移并混淆了迭代。 很高兴知道这篇文章中提到的所有方法,但最有效的是我正在寻找的东西:)
附录:这在我的linux机器(ubuntu 9.10,perl 5.10)上运行完美(我的意思是每个注释行),但上面的错误是在使用perl 5.005_03工作的Windows 7机箱上。 升级不是一种选择。
由于
答案 0 :(得分:6)
为什么不从一开始就哭?
@array = grep { !/hi/ } @array;
# Or, for *referenced* array
@$arrayRef = grep { !/hi/ } @$arrayRef;
一小组注释,用于澄清评论中出现的问题:
此方法(或使用grep
包含原始海报代码的任何方法)将按新结果数组的大小增加脚本的内存使用量。
E.g。如果脚本(没有第一个阵列)占用10MB内存,原始阵列需要15MB内存,结果阵列占用14MB内存,那么程序的总内存占用量将增加 <{1}}正在运行时,25MB到39MB。
一旦grep
comlpetes,原始数组使用的内存将可用于垃圾收集(有一些警告与此帖无关)。
然而 - 这很重要 - 即使最初的15MB数据是垃圾回收, Perl也不会将15MB返回到操作系统 - 例如脚本的内存占用将保持39MB ,即使在垃圾回收后也不会降至24MB。
好的一面是,在程序的整个生命周期中,释放的15MB可用于内存分配(不考虑内存碎片问题) - 因此,如果您的脚本需要分配额外的1MB,5MB ,或15MB内存,其内存占用量不会超过39MB的高点。如果需要17MB的额外内存,最终的内存占用量仅为41MB,而不是56MB。
如果这种记忆算法对您不满意(例如,如果您的原始阵列是500MB并且您不愿意容忍程序内存占用量增加到1GB),那么下面的Dallaylaen's answer是一个很好的执行任务的算法没有额外的内存分配
答案 1 :(得分:4)
撤消循环的顺序,您可以使用splice
:
for(my $i = $#array; $i >= 0; --$i) {
#...
}
答案 2 :(得分:2)
如果你做@$array = grep { ... } @$array
,为什么不坚持使用grep { $_ !~ /hi/ }
?
但是,如果你真的受内存限制,你可以尝试从顶部开始:
my $i = @$array;
while ($i-->0) {
splice @$array, $i, 1 if $array->[$i] =~ /hi/;
};
但这有一个n ^ 2的最坏情况,所以用C-with-dollars而不是真正的Perl编写可能更好:
my $array = [qw(ok now what is hi the matter)];
my $to = 0;
# move elements backwards
for (my $from=0; $from < @$array; $from++) {
$array->[$from] =~ /hi/ and next;
$array->[$to++] = $array->[$from];
};
# remove tail
splice @$array, $to;
print join ":", @$array;
我仍然不知道为什么delete $array->[$i]
不起作用,它适用于我目前掌握的perl 5.10和5.8。
答案 3 :(得分:0)
sub zonk {
$array=shift; # this is a reference of an array
foreach $i (0..$#$array) { # I saw some say to avoid last element to get size
print $array->[$i],"\n";
if ($array->[$i] =~ /hi/) {
delete @{$array}[$i];
}
}
@$array = grep{$_} @$array; # removes empty elements
}
zonk(\@a);
print join(':',@a);
答案 4 :(得分:0)
循环遍历每个键,将每个项目推送到一个数组中,然后使用最终删除 - 一举!
foreach my $key(keys %$my_array) {
my $val= $my_array->{$key};
if ($val eq "BAD") {
push (@unwanted,$key);
}
}
delete @{$my_array}{@unwanted};