NAME
Iterator::Simple - Simple iterator and utilities
SYNOPSIS
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 iteratewhile(defined($_ = $iterator->())) {print;}while(defined($_ = $iterator->next)) {print;}while(<iterator>) {print;}
DESCRIPTION
Iterator::Simple is yet another general-purpose iterator utilities.
Rather simple, but powerful and fast iterator.
FUNCTIONS
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);
- iterator { CODE }
-
Iterator constructor. CODE returns a value on each call, and if it is exhausted, returns undef. Therefore, you cannot yields undefined value as a meaning value. If you want, you could use Iterator module which can do that.
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:
- •
-
just call it
while(defined($_ = $iterator->())) {print "$_\n";}
- •
-
"next"methodwhile(defined($_ = $iterator->next)) {print "$_\n";}
- •
-
<> operator
while(<$iterator>) {print "$_\n";}
- is_iterator($object)
-
If
$objectis an iterator created by Iterator::Simple, returns true. False otherwise.
- iter($object)
-
This function auto detects what
$objectis, and automatically turns it into an iterator. Supported objects are:- •
-
Iterator made with Iterator::Simple.
- •
-
Object that implements
"__iter__"method.
- •
-
Object that overloads '<>' or has
"next"method.
- •
-
Object that overloads '&{}'.(as iterator function.)
- •
-
Object that overloads '@{}'.(with
"iarray()")
- •
-
ARRAY reference. (
"iarray()")
- •
-
CODE reference. (as iterator function.)
- •
-
GLOB reference.
- •
-
nothing (
"iter()".) (empty iterator.)
If it fails to convert, runtime error.
- is_iterable($object)
-
return true if
$objectcan be converted with"iter($object)"
- list($object)
-
This function converts
$objectinto single array referece.- •
-
ARRAY reference.
- •
-
GLOB reference.
- •
-
Iterator made with Iterator::Simple.
- •
-
Object that overloads '@{}' operator.
- •
-
Object that implements '__iter__' method.
- •
-
Object that overloads '<>' operator or has
"next"method.
- •
-
nothing (i.e. list() returns []);
If it fails to convert, runtime error.
Note that after
"list($iterator)", that iterator is not usable any more.
- imap { CODE } $iterable
-
This is the iterator version of
"map". Returns an iterator which yields the value from source iterator modified by CODE.
- igrep { CODE } $iterable
-
This is the iterator version of
"grep". Returns an iterator which yields the value from source iterator only when CODE returns true value.
- iflatten $iterable
-
When
$iterableyields another iterator, iterate it first.$subitr = iter([10, 11,12]);$source = iter([ 1, 2, $subitr, 4]);$flattened = iflatten $source;# yields 1, 2, 10, 11, 12, 4.
- ifilter $iterable, sub{ CODE }
-
This is the combination of imap, igrep, iflatten. it supports modify (imap) , skip (igrep), and inflate (iflatten). but it should be faster than combination of them.
For example:
$combination = iflattenimap { $_ 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'; #skipreturn iter(['whoa', 'who']) if $_ eq 'baz'; #inflatereturn ":$_:"; # modify};Both of them will yields
':foo:', 'whoa', 'who', ':fiz:'.
- ichain($iterable, $iterable2, ...)
-
This function returns an iterator which chains one or more iterators. Iterates each iterables in order as is, until each iterables are exhausted.
Example:
$itr1 = iter(['foo', 'bar', 'baz']);$itr2 = iter(['hoge', 'hage']);$chained = ichain($itr1, $itr2);# yields 'foo', 'bar', 'baz', 'hoge', 'hage'.
- ienumerate($iterable)
-
This function returns an iterator yields like:
$ary = iter(['foo', 'bar', 'baz', ... ]);$iter = ienumerate $ary;# yields [0, 'foo'], [1, 'bar'], [2, 'baz'], ...
- izip($iterable, $iterable2, ...);
-
Accepts one or more iterables, returns an iterator like:
$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.
- islice($iterable, $start, $end, $step)
-
Same as islice of itertools in Python. If
$endis undef or negative value, it iterates source until it is exhausted.$stepdefaults to 1. 0 or negative step value is prohibited.$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.
- ihead($count, $iterable)
-
islice($iterable, 0, $count, 1);
- iskip($count, $iterable)
-
islice($iterable, $count, undef, 1);
- iarray($arrayref);
-
Turns array reference into an iterator. Used in
"iter($arrayref)". You do not have to use this function directly, because"iter($arrayref)"is sufficient.
OO INTERFACE
Iterator used in Iterator::Simple is just a code reference blessed in Iterator::Simple::Iterator. This class implements several method and overloads some operators.
- Itrator::Simple::Iterator->new($coderef)
-
Just bless
$coderefin Iterator::Simple::Iterator and returns it.
- $iterator->next
-
Call underlying code.
- $iterator->__iter__
-
Returns self. You don't need to use this.
- Overloaded operators.
-
- •
-
Read filehandle operator '<>'
Overloading '<>' makes this possible like:
print while <$iterator>;
- •
-
Pipe.. bit_OR? .. No, pipe!
$iterator | $coderef1 | $coderef2;is equivalent to:
$iterator->filter($coderef1)->filter($coderef2);is equivalent to:
ifilter(ifilter($iterator, $coderef1), $coderef2);
- $iterator->filter($coderef)
- $iterator->flatten()
- $iterator->chain($another, ..)
- $iterator->zip($another, ..)
- $iterator->enumerate()
- $iterator->slice($start, $end, $step)
- $iterator->head($count)
- $iterator->skip($count)
-
For example,
$iterator->flatten() is equivalent to"iflatten $iterator".
TIPS
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.
Why Not Iterator.pm
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.
AUTHOR
Rintaro Ishizaki <[email protected]>
LICENSE
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
SEE ALSO
- •
-
Iterator - Feature rich another iterator class.
- •
-
Iterator::Util - Utilities which uses Iterator. Many of filter functions are from this module.