Perl 5 - Iterator

I implemented a simple iterator in perl. I usually work with C # and often use iterators and functional programming. So I thought it would be easy to get some basics working in perl.

The problem is that I am getting some bad performance, I do not expect it to be faster than for foreach, but I thought that someone could give me some idea on how to speed it up.

Here is the courage of my package:

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}->();
}

Lets do this:

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

Not screaming ... bye.

Also allows you to use some functional code:

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

To sum all the even values ​​of the array.

My bottleneck is the iteration code:

$this->{Sub} = sub { 
   my @array = @{$this->{Array}};
   return $#array >= $this->{Index} ? $array[$this->{Index}++] : undef;
  };

Any pointers to speed this up?

+5
9

, , , , , . - , , .

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}
} 

, next , :

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

while (defined (my $x = $next->()) {...}

30-40% .

List::Gen curse

+5
+5

:

my @array = @{$this->{Array}};

@array, , . $#{$this->{Array}}, .

+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}++];
}
+5

grep List::Util:

use List::Util 'sum';
say sum grep { not $_ % 2 } (1 .. 10); // 30

, , , . , Perl.

+4

List:: Util List:: MoreUtils , . perl5i .

:

use perl5i::2;

my @nums = (0..100);
my $sumEven = @nums->grep(sub { $_ % 2 == 0 })->reduce(sub { $a+$b });

say $sumEven;
+4

Perl:

my @array = (1, 2, 3, 4);
while (my $i = shift @array)
{
    print $i . "\n";
}
+2

CPAN , , .

, :

#set default values
$this->{Array} = @_[1];

, $_[1]. @_[1] . , - . , , @_ [1] , , ( , perl 5.10). Perl 6 , "" Perl; -)

+2

. , $this->{Array}, @array, :

my @array = @{$this->{Array}};

Also, if you know you will stop when you click undef, you don’t even need to check the borders.

$this->{Sub} = sub { return $this->{Array}[++$this->{Index}]; }

Anything you need. When {Index}out of range, it will return undef.

Alternatively, you can write your expression in Perl, for example:

$sum += $_ foreach grep { $_ % 2 == 0 } @array;
+2
source

All Articles