Arrays 切掉第n个元素的倍数
我有一个超过10k元素的列表。我想删除每三个元素 比如说,Arrays 切掉第n个元素的倍数,arrays,perl,list,grep,Arrays,Perl,List,Grep,我有一个超过10k元素的列表。我想删除每三个元素 比如说, @testlists = qw (helloworld sessions first.cgi login localpcs depthhashes.cgi search view macros plugins ...) ; 我想先从原始数组中删除first.cgi,depthhashses.cgi,宏等等。Grep函数稍微慢一点。请建议我一个更快的grep搜索或任何其他类似的子程序。非常感谢您的任何帮助我不确定您使用grep的意思,
@testlists = qw (helloworld sessions first.cgi login localpcs depthhashes.cgi search view macros plugins ...) ;
我想先从原始数组中删除
first.cgi
,depthhashses.cgi
,宏
等等。Grep函数稍微慢一点。请建议我一个更快的grep搜索或任何其他类似的子程序。非常感谢您的任何帮助我不确定您使用grep的意思,但也许您的意思是这样的
for $i (0 .. $#testlists) {
if (($i % 3) == 2) {
delete $testlists[$i];
}
}
# Demonstrate the values.
foreach $e (@testlists) {
print "$e\n";
}
使用数组切片
@testlists = @testlists[ grep { ($_+1) % 3 } 0..$#testlists ];
我可以想出一些解决办法:
- 关于指数可分性的Grep
my $i = 0; @testlist = grep { ++$i % 3 } @testlist;
- 重复剪接
(for (my $i = 2; $i < $#testlist; $i += 2) { splice @testlist, $i, 1; }
是mob的解决方案) 这可能是因为它将大部分实际工作卸载到C级实现中,避免了分配和昂贵的Perl级操作 有了10000个元素列表,优势将转移到其他解决方案。实际上,拼接解决方案的算法复杂度非常差,因为它在所有拼接位置之后移动所有元素,这意味着最后一个元素移动了近3333次:slice
Rate splice slice grep copy splice 42.7/s -- -35% -42% -49% slice 65.3/s 53% -- -12% -23% grep 74.2/s 74% 14% -- -12% copy 84.4/s 98% 29% 14% --
以下是。阿蒙的
不执行作业。我不知道你还想要什么。从perldoc,拷贝可以调整为快30%
结果(10000个要素): 基准:my $i = 1; my $j = 1; while ($i < @a) { $a[++$j] = $a[$i+=2]; $a[++$j] = $a[++$i]; } $#a = $j-1 if @a>2;
use strict; use warnings; use Benchmark qw( cmpthese ); my @testlist = qw( helloworld sessions first.cgi login localpcs depthhashes.cgi search view macros ); @testlist = ( @testlist ) x ( 10000 / @testlist ); sub grep_a { my @a = @testlist; my $i = 0; @a = grep { ++$i % 3 } @a; 1 } sub copy1_a { my @a = @testlist; my @b; $#b = $#a; @b = (); # Does absolutely nothing in this benchmark because of optimisations in Perl. for (my $i = 0; $i < @a; $i += 3) { push @b, @a[$i, $i+1]; } 1 } sub copy2_a { my @a = @testlist; my $i = 1; my $j = 1; while ($i < @a) { $a[++$j] = $a[$i+=2]; $a[++$j] = $a[++$i]; } $#a = $j-1 if @a>2; 1 } sub splice_a { my @a = @testlist; for (my $i = 2; $i < $#a; $i += 2) { splice @a, $i, 1; } 1 } sub grep_r { my $r = [ @testlist ]; my $i = 0; $r = sub { \@_ }->( grep { ++$i % 3 } @$r ); 1 } sub copy1_r { my $r = [ @testlist ]; my @b; $#b = $#$r; @b = (); # Does absolutely nothing in this benchmark because of optimisations in Perl. for (my $i = 0; $i < @$r; $i += 3) { push @b, @$r[$i, $i+1]; } $r = \@b; 1 } sub copy2_r { my $r = [ @testlist ]; my $i = 1; my $j = 1; while ($i < @$r) { $r->[++$j] = $r->[$i+=2]; $r->[++$j] = $r->[++$i]; } $#$r = $j-1 if @$r>2; 1 } sub splice_r { my $r = [ @testlist ]; for (my $i = 2; $i < $#$r; $i += 2) { splice @$r, $i, 1; } 1 } cmpthese(-3, { grep_a => \&grep_a, copy1_a => \©1_a, copy2_a => \©2_a, splice_a => \&splice_a, grep_r => \&grep_r, copy1_r => \©1_r, copy2_r => \©2_r, splice_r => \&splice_r, });
你可能会对我的答案感兴趣。使用严格; 使用警告; 使用基准qw(CMP准则); my@testlist=qw(helloworld sessions first.cgi login localpcs depthhashes.cgi search view宏); @testlist=(@testlist)x(10000/@testlist); 子grep_a{my@a=@testlist;my$i=0;@a=grep{++$i%3}@a;1} 子副本1_a{my@a=@testlist; 我的@b; $#b=$#a;@b=();#在这个基准测试中完全不做任何事情,因为Perl中进行了优化。 对于(我的$i=0;$i<@a;$i+=3){ 按@b,@a[$i,$i+1]; } 1. } 子副本2_a{my@a=@testlist; 我的$i=1; 我的$j=1; 而($i<@a){ $a[+$j]=$a[$i+=2]; $a[++$j]=$a[++$i]; } $#a=$j-1,如果@a>2; 1. } 子拼接_a{my@a=@testlist; 对于(我的$i=2;$i<$#a;$i+=2){ 拼接@a$i,1; } 1. } sub grep_r{my$r=[@testlist];my$i=0;$r=sub{\@}->(grep{++$i%3}@$r);1} 子副本1_r{my$r=[@testlist]; 我的@b; $#b=$#$r;@b=();#由于Perl中的优化,在这个基准测试中完全不做任何事情。 对于(我的$i=0;$i<@$r;$i+=3){ 按@b,@$r[$i,$i+1]; } $r=\@b; 1. } 子副本2_r{my$r=[@testlist]; 我的$i=1; 我的$j=1; 而($i<@$r){ $r->[++$j]=$r->[$i+=2]; $r->[++$j]=$r->[++$i]; } $#$r=$j-1如果@$r>2; 1. } 子拼接{my$r=[@testlist]; 对于(我的$i=2;$i<$\r;$i+=2){ 拼接@$r$i,1; } 1. } cmpthese(-3{ grep\u a=>\&grep\u a, copy1\u a=>\©1\u a, copy2\u a=>\©2\u a, 接头a=>\&接头a, grep\u r=>\&grep\u r, copy1\u r=>\©1\u r, copy2\u r=>\©2\u r, 拼接\u r=>\&拼接\u r, });
和sub{\\}->(grep{++$i%3}$$r)
之间是否有显著差异?@mpapec,一个比另一个快50%,因为它不复制任何标量。这很好,你能指出它背后的原理吗?也许列表停留在堆上,而函数只是返回它所看到的[grep{++$i%3}$$r]
?嗯?不执行@
是指不这样做更快。@mpapec,$scalar2=$scalar1
基本上与[EXPR]
相同。它做作业<代码>\@do{my@anon=(EXPR);\@anon}
,虽然exists()会为删除的条目返回false,删除数组元素永远不会改变现有值的索引
@mpapec我仍然是Perl的普通用户,事实上,非常感谢您提供的信息。对数组值调用delete是不推荐的,可能会在未来的Perl版本中被删除。
my $i = 1; my $j = 1; while ($i < @a) { $a[++$j] = $a[$i+=2]; $a[++$j] = $a[++$i]; } $#a = $j-1 if @a>2;
my $i = 0; my $ref = sub { \@_ }->( grep { ++$i % 3 } @a );
>perl a.pl Rate splice_a splice_r grep_a copy1_a copy1_r copy2_r copy2_a grep_r splice_a 52.8/s -- -0% -51% -54% -56% -66% -66% -68% splice_r 52.9/s 0% -- -51% -54% -55% -66% -66% -68% grep_a 107/s 103% 103% -- -7% -10% -30% -31% -34% copy1_a 115/s 118% 117% 7% -- -3% -25% -26% -30% copy1_r 119/s 125% 124% 11% 3% -- -23% -23% -27% copy2_r 154/s 191% 190% 43% 34% 29% -- -0% -6% copy2_a 154/s 192% 192% 44% 34% 30% 0% -- -6% grep_r 163/s 209% 209% 52% 42% 37% 6% 6% --
use strict; use warnings; use Benchmark qw( cmpthese ); my @testlist = qw( helloworld sessions first.cgi login localpcs depthhashes.cgi search view macros ); @testlist = ( @testlist ) x ( 10000 / @testlist ); sub grep_a { my @a = @testlist; my $i = 0; @a = grep { ++$i % 3 } @a; 1 } sub copy1_a { my @a = @testlist; my @b; $#b = $#a; @b = (); # Does absolutely nothing in this benchmark because of optimisations in Perl. for (my $i = 0; $i < @a; $i += 3) { push @b, @a[$i, $i+1]; } 1 } sub copy2_a { my @a = @testlist; my $i = 1; my $j = 1; while ($i < @a) { $a[++$j] = $a[$i+=2]; $a[++$j] = $a[++$i]; } $#a = $j-1 if @a>2; 1 } sub splice_a { my @a = @testlist; for (my $i = 2; $i < $#a; $i += 2) { splice @a, $i, 1; } 1 } sub grep_r { my $r = [ @testlist ]; my $i = 0; $r = sub { \@_ }->( grep { ++$i % 3 } @$r ); 1 } sub copy1_r { my $r = [ @testlist ]; my @b; $#b = $#$r; @b = (); # Does absolutely nothing in this benchmark because of optimisations in Perl. for (my $i = 0; $i < @$r; $i += 3) { push @b, @$r[$i, $i+1]; } $r = \@b; 1 } sub copy2_r { my $r = [ @testlist ]; my $i = 1; my $j = 1; while ($i < @$r) { $r->[++$j] = $r->[$i+=2]; $r->[++$j] = $r->[++$i]; } $#$r = $j-1 if @$r>2; 1 } sub splice_r { my $r = [ @testlist ]; for (my $i = 2; $i < $#$r; $i += 2) { splice @$r, $i, 1; } 1 } cmpthese(-3, { grep_a => \&grep_a, copy1_a => \©1_a, copy2_a => \©2_a, splice_a => \&splice_a, grep_r => \&grep_r, copy1_r => \©1_r, copy2_r => \©2_r, splice_r => \&splice_r, });