Arrays 切掉第n个元素的倍数

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的意思,

我有一个超过10k元素的列表。我想删除每三个元素

比如说,

@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;
    }
    
    slice
    是mob的解决方案)

    这可能是因为它将大部分实际工作卸载到C级实现中,避免了分配和昂贵的Perl级操作

    有了10000个元素列表,优势将转移到其他解决方案。实际上,拼接解决方案的算法复杂度非常差,因为它在所有拼接位置之后移动所有元素,这意味着最后一个元素移动了近3333次:

             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%     --
    

    以下是。

    阿蒙的
    拷贝可以调整为快30%

    my $i = 1;
    my $j = 1;
    while ($i < @a) {
       $a[++$j] = $a[$i+=2];
       $a[++$j] = $a[++$i];
    }
    
    $#a = $j-1 if @a>2;
    
    结果(10000个要素):

    基准:

    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 => \&copy1_a,
       copy2_a => \&copy2_a,
       splice_a => \&splice_a,
    
       grep_r => \&grep_r,
       copy1_r => \&copy1_r,
       copy2_r => \&copy2_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)
    [grep{++$i%3}$$r]
    之间是否有显著差异?@mpapec,一个比另一个快50%,因为它不复制任何标量。这很好,你能指出它背后的原理吗?也许列表停留在堆上,而函数只是返回它所看到的
    @
    ?嗯?不执行
    $scalar2=$scalar1
    是指不这样做更快。@mpapec,
    [EXPR]
    基本上与
    do{my@anon=(EXPR);\@anon}
    相同。它做作业<代码>\@
    不执行作业。我不知道你还想要什么。从perldoc,
    虽然exists()会为删除的条目返回false,删除数组元素永远不会改变现有值的索引
    对数组值调用delete是不推荐的,可能会在未来的Perl版本中被删除。
    @mpapec我仍然是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 => \&copy1_a,
       copy2_a => \&copy2_a,
       splice_a => \&splice_a,
    
       grep_r => \&grep_r,
       copy1_r => \&copy1_r,
       copy2_r => \&copy2_r,
       splice_r => \&splice_r,
    });