该数组有很多数据,我需要删除两个元素。
以下是我正在使用的代码段,
my @array = (1,2,3,4,5,5,6,5,4,9);
my $element_omitted = 5;
@array = grep { $_ != $element_omitted } @array;
该数组有很多数据,我需要删除两个元素。
以下是我正在使用的代码段,
my @array = (1,2,3,4,5,5,6,5,4,9);
my $element_omitted = 5;
@array = grep { $_ != $element_omitted } @array;
Answers:
如果您已经知道要删除的元素的索引,请使用splice。
如果您正在搜索,则Grep可以工作。
如果您需要做很多这样的事情,那么将数组保持在已排序的顺序中,将会获得更好的性能,因为您可以进行二进制搜索来找到必要的索引。
如果在您的上下文中有意义,则可能要考虑对已删除的记录使用“魔术值”,而不是删除它们,以节省数据移动-例如,将已删除的元素设置为undef。当然,这有其自身的问题(如果您需要了解“实时”元素的数量,需要分别对其进行跟踪等),但是根据您的应用程序可能会遇到麻烦。
编辑实际上,现在让我再看一遍-不要使用上面的grep代码。找到要删除的元素的索引,然后使用splice删除它,效率会更高(您的代码会累积所有不匹配的结果。)
my $index = 0;
$index++ until $arr[$index] eq 'foo';
splice(@arr, $index, 1);
那将删除第一次出现。删除所有出现的事件非常相似,除了您将希望一次性获得所有索引:
my @del_indexes = grep { $arr[$_] eq 'foo' } 0..$#arr;
其余内容供读者练习-请记住,阵列在拼接时会发生变化!
Edit2 John Siracusa正确指出我的示例中有一个错误。.修复,对此感到抱歉。
my ($index) = grep { $arr[$_] eq 'foo' } 0..$#arr; if (defined $index) {splice(@arr, $index, 1); }
-第一场比赛
文章的其余部分记录了将元素的测试转换为splice
偏移量的难度。因此,使其成为更完整的答案。
查看您必须经过的旋转,以拥有有效的算法(即一次通过),以将列表项上的测试转换为索引。而且根本不是那么直观。
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;
}
我发现最好的是“ undef”和“ grep”的组合:
foreach $index ( @list_of_indexes_to_be_skiped ) {
undef($array[$index]);
}
@array = grep { defined($_) } @array;
绝招!费德里科
grep
最后将其删除。
可以肯定的是,我已经对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定义的索引来实现remove函数是没有用的。只需grep-remove直接。
在测试之前,我认为“ map1”将是最有效的……我猜应该更多地依赖于Benchmark。;-)