Algorithm-Odometer-Tiny
view release on metacpan or search on metacpan
lib/Algorithm/Odometer/Tiny.pm view on Meta::CPAN
#!perl
use warnings;
use strict;
# SEE THE END OF THIS FILE FOR AUTHOR, COPYRIGHT AND LICENSE INFORMATION
{ package Algorithm::Odometer::Tiny;
our $VERSION = "0.04";
use Carp;
use overload '<>' => sub {
my $self = shift;
return $self->() unless wantarray;
my @all;
while (defined( my $x = $self->() ))
{ push @all, $x }
return @all;
};
sub new { ## no critic (RequireArgUnpacking)
my $class = shift;
return bless odometer(@_), $class;
}
sub odometer { ## no critic (RequireArgUnpacking)
croak "no wheels specified" unless @_;
my @w = map { [ 1, ref eq 'ARRAY' ? @$_ : $_ ] } @_;
my $done;
return sub {
if ($done) { $done=0; return }
my @cur = map {$$_[$$_[0]]} @w;
for(my $i=$#w;$i>=0;$i--) {
last if ++$w[$i][0]<@{$w[$i]};
$w[$i][0]=1;
$done=1 unless $i;
}
return wantarray ? @cur : join '', map {defined()?$_:''} @cur;
};
}
}
# Possible To-Do for Later: Generate regexes based on the wheels?
1;
__END__
=head1 Name
Algorithm::Odometer::Tiny - Generate "base-N odometer" permutations (Cartesian product / product set)
=head1 Synopsis
use Algorithm::Odometer::Tiny;
my $odometer = Algorithm::Odometer::Tiny->new( [qw/a b c/], [qw/1 2/] );
print $odometer->(), "\n"; # prints "a1"
my $val = <$odometer>; # $val is "a2"
my @val = $odometer->(); # @val is ("b", "1")
my @rest = <$odometer>; # only in Perl 5.18+: get remaining values
=head1 Description
This class implements the permutation algorithm described in I<[1]>
as an iterator. An "odometer" has a number of "wheels", each of which
can have a different number of positions. On each step, the rightmost
wheel is advanced to the next position, and if it wraps around, the
next higher wheel is incremented by one, and so on - it is the same
basic algorithm that we use to count from 0 to 100 and onwards,
except with different "digits".
The constructor of this class takes a list of array references, each
of which represents a wheel in the odometer. The constructor returns
an object of this class, which can be called as a code reference
(C<< $odometer->() >>), or the C<< <> >> I/O operator can be used to
read the next item. Calling the code reference or C<< <> >> operator
in scalar context returns the current state of the wheels joined
together as a string, while calling the code reference in list
context returns the current state of the wheels as a list of
individual values. In Perl 5.18 and above, calling the C<< <> >>
operator in list context will return all of the (remaining) values in
the sequence as strings. In scalar context, the iterator will return
C<undef> once, and then start the sequence from the beginning.
This class is named C<::Tiny> because the code for the odometer fits
( run in 0.695 second using v1.01-cache-2.11-cpan-39bf76dae61 )