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