一次在数组的N个元素上运行函数

时间:2014-06-19 14:52:06

标签: arrays perl

让我们说我有一个数组my @arr,假设长度为240(但这个长度是可变的)。我怎样才能一次在该数组的每个N元素上运行一个函数?

例如,如果N = 100,该函数将首先在@arr[0..99]上运行,然后在@arr[100..199]运行,最后运行@arr[200..239]

我的想法是让某种循环通过将N个元素连接在一起来创建一个长度为N的临时数组,但这些似乎过于复杂。

3 个答案:

答案 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);
}