Perl 5 - 迭代器

jon*_*ers 5 perl iterator functional-programming perl-module

我在perl中实现了一个简单的迭代器.我通常使用C#,并且经常使用迭代器和函数式编程.所以我认为在perl中使用一些基础知识会很简单.

问题是,我的性能有些不好,我不希望比forforeach更快,但我认为有人可以给我一些关于如何加快速度的见解.

这是我的包裹的胆量:

package Iterator;
use strict;

#Constructor for Iterator type
sub new {
  my $type = $_[0];
  my $this = {};

  #set default values
  $this->{Array} = @_[1];
  $this->{Index} = 0;
 $this->{Sub} = sub { 
   my @array = @{$this->{Array}};
   return $#array >= $this->{Index} ? $array[$this->{Index}++] : undef;
  };

  #return self
  bless($this, $type);
  return $this;
}

#Iterates next
sub Next {
 return $_[0]->{Sub}->();
}
Run Code Online (Sandbox Code Playgroud)

允许您这样做:

my $iterator = Iterator->new(\@array);
while (defined(my $current = $iterator->Next())) {
  print $current, "\n";
}
Run Code Online (Sandbox Code Playgroud)

不华而不实......

还启用了一些像这样的功能代码:

my $sum = 0;
Iterator
  ->new(\@array)
  ->Where(sub { $_[0] % 2 == 0 })
  ->ForEach(sub { $sum += $_[0] });
Run Code Online (Sandbox Code Playgroud)

这将总结数组的所有偶数值.

我的瓶颈是迭代代码:

$this->{Sub} = sub { 
   my @array = @{$this->{Array}};
   return $#array >= $this->{Index} ? $array[$this->{Index}++] : undef;
  };
Run Code Online (Sandbox Code Playgroud)

是否有任何提高速度的指针?

Dav*_*oss 5

您可能会发现阅读一些高阶Perl很有用.


ara*_*nid 5

这一行:

my @array = @{$this->{Array}};
Run Code Online (Sandbox Code Playgroud)

将数组复制到@array中,我认为你不想这样做.只是$#{$this->{Array}}找到你的数组的端点.


tst*_*ter 5

更高效的版本:

package Iterator;
use strict;

#Constructor for Iterator type
sub new {
  my $type = shift;
  my $array = shift;
  my $this = {};
  $this->{array} = $array;
  $this->{index} = 0;
  bless($this, $type);
  return $this;
}

#Iterates next
sub Next {
  my $this = shift;
  return $this->{array}->[$this->{index}++];
}
Run Code Online (Sandbox Code Playgroud)

  • @ Jonathan.Peppers,如果你担心班次与$ _ [0]的表现那么你就会担心错误的事情.函数调用本身比这些操作要昂贵得多. (4认同)

Eri*_*rom 5

这里游戏有点晚了,但是由于你关注性能,迭代器类型代码中最大的瓶颈之一就是基于哈希的对象的字段需要在每次访问时被取消引用.解决此问题的一种方法是使用闭包,其中字段在变量上关闭,从而避免不必要的解除引用.

在我的模块List :: Gen中,它包含一个相当高效的惰性列表实现,我编写了实用程序函数curse,它使基于闭包的对象的行为与普通的Perl对象相同.

这是一个用你编写的迭代器类的简短例子curse.在一个简单的基准测试中,总计1000个数字,这个方法的速度是你的两倍,即使在解决了其他答案中提到的所有低效问题之后.

{package Iterator;
    use List::Gen 'curse';
    sub new {
        my ($class, $array) = @_;
        my $index = 0;
        curse {
            next  => sub {$$array[$index++]},
            index => sub :lvalue {$index},
        } => $class
    }
    sub reset {shift->index = 0}
} 
Run Code Online (Sandbox Code Playgroud)

如果你真的想要更快的速度,因为这个next方法不需要传递任何东西,你甚至可以写:

my $next = $iterator->can('next');

while (defined (my $x = $next->()) {...}
Run Code Online (Sandbox Code Playgroud)

与普通方法调用相比,这将使您的速度提升30%到40%.

您可以阅读List::Gen更高级用法的来源curse