| Iterator::Simple(3pm) | User Contributed Perl Documentation | Iterator::Simple(3pm) |
Iterator::Simple - Simple iterator and utilities
use Iterator::Simple;
sub foo {
my $max = shift;
my $i = 0;
iterator {
return if $i > $max;
$i++;
}
}
my $iterator = foo(20); # yields 0,1,2, ..., 19, 20;
$iterator = imap { $_ + 2 } $iterator; # yields 2,3,4,5, ... ,20,21,22
$iterator = igrep { $_ % 2 } $iterator; # yields 3,5,7,9, ... ,17,19,21
# iterable object
$iterator = iter([qw(foo bar baz)]); # iterator from array ref
$iterator = iter(IO::File->new($filename)); # iterator from GLOB
# filters
$iterator = ichain($itr1, $itr2); # chain iterators;
$iterator = izip($itr1, $itr2); # zip iterators;
$iterator = ienumerate $iterator; # add index;
# general filter
$iterator = ifilter $iterator, sub {
return $_ if /^A/;
return;
}
# how to iterate
while(defined($_ = $iterator->())) {
print;
}
while(defined($_ = $iterator->next)) {
print;
}
while(<iterator>) {
print;
}
Iterator::Simple is yet another general-purpose iterator utilities.
Rather simple, but powerful and fast iterator.
Iterator::Simple doesn't export any functions by default. please import them like:
use Iterator::Simple qw(iter list imap);
For all functions:
use Iterator::Simple qw(:all);
Generally, you can implement iterator as a closure like:
use Iterator::Simple qw(iterator);
sub fibonacci {
my($s1, $s2, $max) = @_;
iterator {
my $rv;
($rv, $s1, $s2) = ($s1, $s2, $s1 + $s2);
return if $rv > $max;
return $rv;
}
}
my $iterator = fiboacci(1, 1, 1000);
You can iterate it in several ways:
while(defined($_ = $iterator->())) {
print "$_\n";
}
while(defined($_ = $iterator->next)) {
print "$_\n";
}
while(<$iterator>) {
print "$_\n";
}
If it fails to convert, runtime error.
If it fails to convert, runtime error.
Note that after "list($iterator)", that iterator is not usable any more.
$subitr = iter([10, 11,12]);
$source = iter([ 1, 2, $subitr, 4]);
$flattened = iflatten $source;
# yields 1, 2, 10, 11, 12, 4.
For example:
$combination = iflatten
imap { $_ eq 'baz' ? iter(['whoa', 'who']) : ":$_:" }
igrep { $_ ne 'bar' }
iter [ 'foo', 'bar', 'baz', 'fiz' ];
$itr = iter [ 'foo', 'bar', 'baz', 'fiz' ];
$filterd = ifilter $itr, sub {
return if $_ eq 'bar'; #skip
return iter(['whoa', 'who']) if $_ eq 'baz'; #inflate
return ":$_:"; # modify
};
Both of them will yields ':foo:', 'whoa', 'who', ':fiz:'.
Example:
$itr1 = iter(['foo', 'bar', 'baz']);
$itr2 = iter(['hoge', 'hage']);
$chained = ichain($itr1, $itr2);
# yields 'foo', 'bar', 'baz', 'hoge', 'hage'.
$ary = iter(['foo', 'bar', 'baz', ... ]);
$iter = ienumerate $ary;
# yields [0, 'foo'], [1, 'bar'], [2, 'baz'], ...
$animals = iter(['dogs', 'cats', 'pigs']);
$says = iter(['bowwow', 'mew', 'oink']);
$zipped = izip($animals, $says);
# yields ['dogs','bowwow'], ['cats','mew'], ['pigs', 'oink'].
Note that when one of source iterables is exhausted, zipped iterator will be exhausted also.
$iter = iter([0,1,2,3,4,5,6,7,8,9,10,11,12]);
$sliced = islice($iter, 3, 13, 2);
# yields 3, 5, 7, 9, 11.
islice($iterable, 0, $count, 1);
islice($iterable, $count, undef, 1);
Iterator used in Iterator::Simple is just a code reference blessed in Iterator::Simple::Iterator. This class implements several method and overloads some operators.
Overloading '<>' makes this possible like:
print while <$iterator>;
$iterator | $coderef1 | $coderef2;
is equivalent to:
$iterator->filter($coderef1)->filter($coderef2);
is equivalent to:
ifilter(ifilter($iterator, $coderef1), $coderef2);
All iterator transformation function calls "iter" function on all source iterables. So you can pass just array reference, GLOB ref, etc.
These examples completely do the right thing:
imap { $_ + 2 } [1, 2, 3, ... ];
ienumerate(\*STDIN);
# DBIx::Class::ResultSet has 'next' method.
ifilter $dbic_resultset, sub {CODE};
You can implement "__iter__" method on your objects in your application. By doing that, your object will be Iterator::Simple friendly :).
Note that "__iter__" method must return an iterator.
There is another iterator module in CPAN, named Iterator and Iterator::Util made by Eric J. Roode that is great solution. Why yet another iterator module? The answer is *Speed*. You use iterator because you have too many data to manipulate in memory, therefore iterator could be called thousands of times, speed is important.
For this simple example:
use Iterator::Util qw(iarray imap igrep);
for(1 .. 100) {
my $itr = igrep { $_ % 2 } imap { $_ + 2 } iarray([1 .. 1000]);
my @result;
while($itr->isnt_exhausted) {
push @result, $itr->value;
}
}
meanwhile:
use Iterator::Simple qw(iarray imap igrep);
for(1 .. 100) {
my $itr = igrep { $_ % 2 } imap { $_ + 2 } iarray([1 .. 1000]);
my @result;
while(defined($_ = $itr->())) {
push @result, $_;
}
}
Iterator::Simple is about ten times faster!
That is natural because Iterator::Simple iterator is just a code reference, while Iterator.pm iterator is full featured class instance. But Iterator::Simple is sufficient for usual demands.
One of most downside of Iterator::Simple is, you cannot yields undef value as a meaning value, because Iterator::Simple thinks it as a exhausted sign. If you need to do that, you have to yield something which represents undef value.
Also, Iterator::Simple cannot determine iterator is exhausted until next iteration, while Iterator.pm has 'is(nt)_exhausted' method which is useful in some situation.
Rintaro Ishizaki <rintaro@cpan.org>
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
| 2022-10-16 | perl v5.36.0 |