如何删除引用数组的元素?

时间:2010-12-11 04:57:47

标签: arrays perl pass-by-reference

我想用子程序从几个大数组中删除元素。我使用引用来避免副本进入子。

@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机箱上。 升级不是一种选择。

由于

5 个答案:

答案 0 :(得分:6)

为什么不从一开始就哭?

@array = grep { !/hi/ } @array;
# Or, for *referenced* array
@$arrayRef = grep { !/hi/ } @$arrayRef;

一小组注释,用于澄清评论中出现的问题:

  1. 此方法(或使用grep包含原始海报代码的任何方法)按新结果数组的大小增加脚本的内存使用量。

    E.g。如果脚本(没有第一个阵列)占用10MB内存,原始阵列需要15MB内存,结果阵列占用14MB内存,那么程序的总内存占用量将增加 <{1}}正在运行时,25MB到39MB。

  2. 一旦grep comlpetes,原始数组使用的内存将可用于垃圾收集(有一些警告与此帖无关)。

  3. 然而 - 这很重要 - 即使最初的15MB数据是垃圾回收, Perl也不会将15MB返回到操作系统 - 例如脚本的内存占用将保持39MB ,即使在垃圾回收后也不会降至24MB。

  4. 好的一面是,在程序的整个生命周期中,释放的15MB可用于内存分配(不考虑内存碎片问题) - 因此,如果您的脚本需要分配额外的1MB,5MB ,或15MB内存,其内存占用量不会超过39MB的高点。如果需要17MB的额外内存,最终的内存占用量仅为41MB,而不是56MB。

  5. 如果这种记忆算法对您不满意(例如,如果您的原始阵列是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};