Как насчет функционального решения общего назначения.
use Carp; # so mapn can croak about errors
sub mapn (&$@) {
my ($sub, $n, @ret) = splice @_, 0, 2;
croak '$_[1] must be >= 1' unless $n >= 1;
while (@_) {
local *_ = \$_[0];
push @ret, $sub->(splice @_, 0, $n)
}
@ret
}
sub by ($@) {mapn {[@_]} shift, @_}
sub every ($@); *every = \&by;
Функция mapn
работает так же, как map
, за исключением того, что первый аргумент после ее блока - это количество элементов, которое нужно взять. Он помещает первый элемент в $_
и все элементы в @_
.
print mapn {"@_\n"} 2 => 1 .. 5;
# prints
1 2
3 4
5
Следующие два идентичных подпрограммы by
и every
создают полезные наречия для различных циклических конструкций. Они обрабатывают список с помощью mapn и возвращают список ссылок на массив нужного размера
print "@$_\n" for every 2 => 1..10;
print map {"@$_\n"} grep {$_->[1] > 5} by 2 => 1..10;
Я считаю, что это более чистое и интуитивно понятное решение, чем natatime, или другое решение, например, стиль c для цикла.