在Perl中,从数组中删除一个值的最佳方法是什么?

89

这个数组有很多数据,我需要删除其中两个元素。

下面是我正在使用的代码片段:

my @array = (1,2,3,4,5,5,6,5,4,9);
my $element_omitted = 5;
@array = grep { $_ != $element_omitted } @array;

4
这将删除三个元素。 - Medlock Perlman
需要从目录列表中删除所有非文件项,"array = grep { -f $_ } array" 对我来说非常有效 :) - taiko
15个回答

1

我使用:

delete $array[$index];

Perldoc delete.


10
数组值上的delete操作可能已经被弃用(请参考文档)。 - Déjà vu
3
在我的 Perl 版本中(5.14),这只是删除存储在该数组索引处的值。 - Rooster
这并不是真正删除你所想的内容。它只是删除了值,使其变为 undef。此外,来自 ringø 链接的文档中指出:“警告:强烈不建议在数组值上调用 delete。删除或检查 Perl 数组元素的存在概念上不一致,可能会导致意外行为。”(文档中的前一段包含所有令人不快的细节)。 - mivk
我的原始答案是10年前的。 - Ariel Monaco

1

为了确保,我已经对grep和map的解决方案进行了基准测试,首先搜索匹配元素(需要删除的元素)的索引,然后直接使用grep删除元素而不搜索索引。 看起来Sam在提问时提出的第一个解决方案已经是最快的。

    use Benchmark;
    my @A=qw(A B C A D E A F G H A I J K L A M N);
    my @M1; my @G; my @M2;
    my @Ashrunk;
    timethese( 1000000, {
      'map1' => sub {
          my $i=0;
          @M1 = map { $i++; $_ eq 'A' ? $i-1 : ();} @A;
      },
      'map2' => sub {
          my $i=0;
          @M2 = map { $A[$_] eq 'A' ? $_ : () ;} 0..$#A;
      },
      'grep' => sub {
          @G = grep { $A[$_] eq 'A' } 0..$#A;
      },
      'grem' => sub {
          @Ashrunk = grep { $_ ne 'A' } @A;
      },
    });

结果是:

这里放结果

Benchmark: timing 1000000 iterations of grem, grep, map1, map2...
  grem:  4 wallclock secs ( 3.37 usr +  0.00 sys =  3.37 CPU) @ 296823.98/s (n=1000000)
  grep:  3 wallclock secs ( 2.95 usr +  0.00 sys =  2.95 CPU) @ 339213.03/s (n=1000000)
  map1:  4 wallclock secs ( 4.01 usr +  0.00 sys =  4.01 CPU) @ 249438.76/s (n=1000000)
  map2:  2 wallclock secs ( 3.67 usr +  0.00 sys =  3.67 CPU) @ 272702.48/s (n=1000000)
M1 = 0 3 6 10 15
M2 = 0 3 6 10 15
G = 0 3 6 10 15
Ashrunk = B C D E F G H I J K L M N

根据经过的时间显示,使用grep或map定义的索引来实现删除功能是没有用的。直接使用grep-remove即可。
在测试之前,我认为"map1"是最有效的...我应该更多地依靠基准测试。;-)

0
如果您知道数组索引,您可以使用delete()来删除它。splice()和delete()之间的区别在于,delete()不会重新编号数组中剩余的元素。

我实际上是指重新编号,根据 Perldoc 的说法,splice() 可以实现。 - Powerlord

0
我曾经写过类似的代码,用于从字符串数组中删除不以SB.1开头的字符串。
my @adoSymbols=('SB.1000','RT.10000','PC.10000');
##Remove items from an array from backward
for(my $i=$#adoSymbols;$i>=0;$i--) {  
    unless ($adoSymbols[$i] =~ m/^SB\.1/) {splice(@adoSymbols,$i,1);}
}

0

这个也很好用:

my @array = (1,2,3,4,5,5,6,5,4,9);
my $element_omitted = 5;
for( my $i = 0; $i < scalar( @array ); $i++ )
{
    splice( @array, $i ), $i-- if( $array[$i] == $element_omitted );
}
say "@array"; # 1 2 3 4 6 4 9

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接