用开始、结束和步骤对字符串进行切片的 Perl 函数

zub*_*nel 1 string perl

我想使用 start、end 和 step 对字符串进行切片。让我们假设开始坐标是 1,结束坐标是 22,步长是 3。切片字符串应该只选择坐标 1、4、7、10、13、16、19、22 中的元素。我写了一个函数 get_subseq这样做。在 Perl 中是否有更短的方法来做到这一点?

sub get_subseq {
    my ( $seq, $start, $end, $step ) = @_;
    my $index = $start;
    while ( $index <= $end ) {
        print substr $seq, $index, 1;
        $index += $step;
    }
}

my $sequence = 'AGGGTAGAGTGAGAAGCACCAGCAGGCAGTAACAGC';

# The result should be GTAGACCC
get_subseq( $sequence, 1, 22, 3 );
Run Code Online (Sandbox Code Playgroud)

zdi*_*dim 7

一种方法:生成索引列表,然后用于map获取相应的字符。

合并成一个声明

use warnings;
use strict;
use feature 'say';

my $seq = q(AGGGTAGAGTGAGAAGCACCAGCAGGCAGTAACAGC); 

my ($beg, $end, $step) = (1, 22, 3); 

my @subseq = 
    map { substr $seq, $_, 1 } 
    grep { ($_-$beg) % $step == 0 } 
    $beg..$end; 

say "@subseq";
Run Code Online (Sandbox Code Playgroud)

这可以在$beg..$end范围内折叠为一次迭代

my @subseq = 
    map { ($_-$beg) % $step == 0 ? substr($seq, $_, 1) : () }
    $beg..$end; 
Run Code Online (Sandbox Code Playgroud)

如果结果需要是一个字符串join列表''(空字符串)。

当然还有一些库可以产生一个跨度范围。该列表::根具有这样的range功能,同时它还具有有趣的算法的整个范围。

use List::Gen qw(range);

my @ss = map { substr $seq, $_, 1 } @{ range $beg, $end, $step };

say "@ss";
Run Code Online (Sandbox Code Playgroud)

range返回一个真正的生成器,它具有有趣的特性。取消引用它会生成值列表。请参阅文档。

虽然这些在单个语句中返回结果,因此“更短”,但我喜欢你自己的问题,它非常清晰,在许多情况下可能更有效。

可以通过(很少)使用 C 样式for循环来进一步简化

for (my $i = $beg; $i <= $end; $i += $step) { print substr $seq, $i, 1 }
Run Code Online (Sandbox Code Playgroud)

另一种方法是将您的字符串分解为其字符列表,然后从该列表中提取所需位置的元素

my @subseq = (split //, $seq)[ @indices ];
Run Code Online (Sandbox Code Playgroud)

您可以在其中使用任何方法来获取@indices(不需要是数组,但可以是在那里生成的列表,例如通过上面使用的任何方法)。这两种方法中哪一种更有效完全取决于细节——序列的长度、要采样的索引跨度的长度、它们的关系、步长。


yst*_*sth 5

没有人喜欢使用正则表达式吗?

join'',substr($seq,$start,$end-$start+1)=~/(?=(.)).{0,$step}/gs
Run Code Online (Sandbox Code Playgroud)

这演示了对这种事情使用正则表达式匹配,其方式有时比循环或拆分和切片更有效。一种更有趣但效率不高的方法是避开 substr:

join '',$seq=~/(?<=.{$start})(?<!..{$end})(?=(.)).{0,$step}/gs
Run Code Online (Sandbox Code Playgroud)