Один способ: создать список индексов и затем использовать 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";
Это можно свернуть в одну итерацию по $beg..$end
range
my @subseq =
map { ($_-$beg) % $step == 0 ? substr($seq, $_, 1) : () }
$beg..$end;
Если результатом должна быть строка join
список по ''
(пустая строка).
И, конечно, есть библиотеки, которые могут произвести Диапазон с шагом. List :: Gen имеет такую функцию range
, хотя он также имеет целый ряд интересных алгоритмов.
use List::Gen qw(range);
my @ss = map { substr $seq, $_, 1 } @{ range $beg, $end, $step };
say "@ss";
Его range
возвращает действительно генератор, который приходит с интересными свойствами. Разыменование создает список значений. См. Документацию.
Хотя они возвращают результат в одном утверждении и, таким образом, «короче», мне нравится ваш собственный ответ на вопрос, который кристально ясен и может быть более эффективным во многих обстоятельствах.
Это может быть упрощено немного (редким!) Использованием C стиля for
l oop
for (my $i = $beg; $i <= $end; $i += $step) { print substr $seq, $i, 1 }
Другой способ заключается в разбить вашу строку на список ее символов, а затем извлечь из этого списка элементы в нужных позициях
my @subseq = (split //, $seq)[ @indices ];
, где вы можете использовать любой метод для получения @indices
(который не обязательно должен быть массивом, но может быть список, сгенерированный прямо здесь, любым способом, использованным выше, например). Какой из этих двух подходов более эффективен, полностью зависит от деталей - длины последовательности, длины диапазона индекса до выборки, их отношения, размера шага.