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

该数组有很多的数据,我需要删除两个元素。

以下是我正在使用的代码片段,

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

如果您已经知道要删除的元素的索引,请使用拼接。

如果你正在searchGrep的作品。

如果你需要做很多这样的工作,如果你的数组按照sorting顺序排列,你会得到更好的性能,因为你可以做二分search来find必要的索引。

如果在您的上下文中有意义,则可以考虑对已删除的logging使用“魔术值”,而不是删除它们,以节省数据移动 – 例如,将删除的元素设置为undef。 当然,这有它自己的问题(如果你需要知道“活”元素的数量,你需要跟踪它分开等),但可能是值得的麻烦取决于你的应用程序。

编辑其实现在我再看看 – 不要使用上面的grep代码。 find要删除的元素的索引会更有效率,然后使用拼接来删除它(您已经累积了所有不匹配的结果的代码)

 my $index = 0; $index++ until $arr[$index] eq 'foo'; splice(@arr, $index, 1); 

这将删除第一次出现。 删除所有的事件是非常相似的,除非你想要一次通过所有的索引:

 my @del_indexes = grep { $arr[$_] eq 'foo' } 0..$#arr; 

其余部分留给读者练习 – 请记住arrays在拼接时会发生变化!

Edit2 John Siracusa正确地指出我在我的例子中有一个错误..修复,抱歉。

拼接将通过索引移除数组元素。 使用grep,如你的例子,search和删除。

这是你会做很多事吗? 如果是这样,你可能要考虑一个不同的数据结构。 Grep每次都要search整个数组,而对于一个大数组可能会相当昂贵。 如果速度是一个问题,那么你可能要考虑使用哈希代替。

在你的例子中,键是数字,值是该数字的元素的数量。

如果你改变

 my @del_indexes = grep { $arr[$_] eq 'foo' } 0..$#arr; 

 my @del_indexes = reverse(grep { $arr[$_] eq 'foo' } 0..$#arr); 

这可以通过首先从数组背面删除元素来避免数组重新编号的问题。 把一个splice()放在foreach循环中清理@arr。 相对简单易读…

 foreach $item (@del_indexes) { splice (@arr,$item,1); } 

我认为你的解决scheme是最简单和最可维护的。

文章的其余部分logging了将元素testing转换为splice偏移的难度。 因此,这是一个更完整的答案。

看看你必须经过的回转有一个有效的(即一个通过)algorithm来将列表项目的testing转化为索引。 而且这不是那么直观。

 sub array_remove ( \@& ) { my ( $arr_ref, $test_block ) = @_; my $sp_start = 0; my $sp_len = 0; for ( my $inx = 0; $inx <= $#$arr_ref; $inx++ ) { local $_ = $arr_ref->[$inx]; next unless $test_block->( $_ ); if ( $sp_len > 0 && $inx > $sp_start + $sp_len ) { splice( @$arr_ref, $sp_start, $sp_len ); $inx = $inx - $sp_len; $sp_len = 0; } $sp_start = $inx if ++$sp_len == 1; } splice( @$arr_ref, $sp_start, $sp_len ) if $sp_len > 0; return; } 

我用:

 delete $array[$index]; 

Perldoc 删除

删除所有出现的“东西”,如果数组。

根据SquareCog的答案:

 my @arr = ('1','2','3','4','3','2', '3','4','3'); my @dix = grep { $arr[$_] eq '4' } 0..$#arr; my $o = 0; for (@dix) { splice(@arr, $_-$o, 1); $o++; } print join("\n", @arr); 

每次我们从@arr删除索引时,下一个要删除的正确索引将是$_-current_loop_step

您可以使用非捕获组和要删除的项目的pipe道定界列表。

 perl -le '@ar=(1 .. 20);@x=(8,10,3,17);$x=join("|",@x);@ar=grep{!/^(?:$x)$/o} @ar;print "@ar"' 

我发现的最好的结果是“undef”和“grep”的组合:

 foreach $index ( @list_of_indexes_to_be_skiped ) { undef($array[$index]); } @array = grep { defined($_) } @array; 

这就是诀窍! 费德里科

如果你知道数组索引,你可以删除()它。 splice()和delete()之间的区别在于,delete()不重新编号该数组的其余元素。

我曾经写过一个类似的代码,用于从string数组中删除不以SB.1开头的string

 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);} }