Iterator::Simple(3pm)

πŸ“¦
version 0.07 Β· 5 versions
, in ubuntu noble, ubuntu resolute, ubuntu stonking

✨ Iterator::Simple ✨

okay so bestie, gather round 🫢 this one's a User Contributed Perl Documentation classic, and it's literally an iterator module that is simple on purpose. Sit with it. It's giving speed.


πŸ“› 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 iterate
while(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. That's the whole vibe β€” it doesn't try to be the fanciest thing in the room, it just moves, and it moves fast. ⭐


🌸 FUNCTIONS

Iterator::Simple doesn't export any functions by default. so you gotta ask nicely, like:

use Iterator::Simple qw(iter list imap);

For all functions β€” the full menu, no crumbs:

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.

🚨 that's the big one, bestie β€” undef here means "we're DONE", so a legit undef value kinda gets read as "the end". If you need real undef values, that's a Iterator module situation, not this one.

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" method
while(defined($_ = $iterator->next)) {
  print "$_\n";
}
  • <> operator
while(<$iterator>) {
  print "$_\n";
}

is_iterator($object)

If $object is an iterator created by Iterator::Simple, returns true. False otherwise. Simple vibe check, that's it. πŸ¦‹

iter($object)

This function auto detects what $object is, 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. no cap, it will just yell at you. 😭

is_iterable($object)

return true if $object can be converted with "iter($object)"

list($object)

This function converts $object into 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. It's spent. Gone. Do not touch it again.

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 $iterable yields 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. one function, all the power. πŸ‘‘

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:'.

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. They go down together, periodt.

islice($iterable, $start, $end, $step)

Same as islice of itertools in Python. If $end is undef or negative value, it iterates source until it is exhausted. $step defaults 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. it's the behind-the-scenes queen πŸ‘‘


πŸ’… 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 $coderef in Iterator::Simple::Iterator and returns it.

$iterator->next

Call underlying code.

$iterator->__iter__

Returns self. You don't need to use this. fr fr, hands off. πŸ™ˆ

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. it'll figure it out. she's smart like that. πŸ’–

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. Non-negotiable bestie.

😀 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. like, thousands. that's the whole plot. πŸ”₯

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! ate. πŸ’…βœ¨

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. so, like, know that going in. πŸ’€


πŸ‘‘ AUTHOR

Rintaro Ishizaki <rintaro@cpan.org>

πŸ’œ 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.

and that's the whole thing, bestie 🫢 this whole page came to you courtesy of perl v5.36.0, dated 2022-10-16 β€” go forth and iterate, you absolute icon πŸŽ€β­πŸ’–

πŸ“¦ where this page comes from