让我们说我有一个数组my @arr
,假设长度为240(但这个长度是可变的)。我怎样才能一次在该数组的每个N元素上运行一个函数?
例如,如果N = 100
,该函数将首先在@arr[0..99]
上运行,然后在@arr[100..199]
运行,最后运行@arr[200..239]
。
我的想法是让某种循环通过将N个元素连接在一起来创建一个长度为N的临时数组,但这些似乎过于复杂。
答案 0 :(得分:1)
while (@arr) {
f(splice(@arr, 0, 100));
}
非破坏性版本:
use List::Util qw( min );
for (my $i=0; $i<@a; $i+=100) {
f(@arr[$i .. min($i+99, $#arr)]);
}
您还可以通过创建别名数组来避免破坏原始数组:
my $shadow = sub { \@_ }->(@arr);
while (@$shadow) {
f(splice(@$shadow, 0, 100));
}
答案 1 :(得分:0)
您可以使用splice
:
sub apply_f_to_n_elements {
my ($f, $n, @elements) = @_;
my @results;
while ( @elements ) {
my @batch = splice(@elements, 0, $n)
push @results,
$f->(@batch);
}
return @results;
}
用法:
apply_f_to_n_elements(\&f, 100, @arr);
或
my @results = apply_f_to_n_elements(\&f, 100, @arr);
以下内容经过优化,可以避免为每个输入制作两个副本(同时仍然保持非破坏性),并进行优化以避免收集回调结果(如果它们将被丢弃):
sub apply_f_to_n_elements {
my $f = shift;
my $n = shift;
if (wantarray) {
my @results;
while (@_) {
push @results, $f->(splice(@_, 0, $n));
}
return @results;
} else {
while (@_) {
$f->(splice(@_, 0, $n));
}
}
}
答案 2 :(得分:0)
使用List::Util qw(min)
效果很好。
但是,如果您需要更多语义解决方案,可以使用List::MoreUtils qw(natatime)
。
use List::MoreUtils qw(natatime);
my $iter = natatime 100, @arr;
while (my @vals = $iter->()) {
f(@vals);
}