Algorithm-Loops
view release on metacpan or search on metacpan
lib/Algorithm/Loops.pm view on Meta::CPAN
MapCarMin {
print pop(), " place goes to ", pop(), ".\n";
} [qw( First Second Third Fourth )],
\@winners;
Same thing (scalar context):
my $report= MapCarMin {
pop(), " place goes to ", pop(), ".\n";
} [qw( First Second Third Fourth )],
\@winners;
Displaying a duration:
my $ran= time() - $^T;
my $desc= join ', ', reverse MapCar {
my( $unit, $mult )= @_;
my $part= $ran;
if( $mult ) {
$part %= $mult;
$ran= int( $ran / $mult );
}
$unit .= 's' if 1 != $part;
$part ? "$part $unit" : ();
} [ qw( sec min hour day week year ) ],
[ 60, 60, 24, 7, 52 ];
$desc ||= '< 1 sec';
print "Script ran for $desc.\n";
=head2 NextPermute*
=over 4
=item NextPermute(\@)
=item NextPermuteNum(\@)
=back
=head3 Introduction
If you have a list of values, then a "permutation" of that list is the
same values but not (necessarily) in the same order.
NextPermute() and NextPermuteNum() each provide very efficient ways of
finding all of the (unique) permutations of a list (even if the list
contains duplicate values).
=head3 Usage
Each time you pass an array to a NextPermute* routine, the elements of
the array are shifted around to give you a new permutation. If the
elements of the array are in reverse-sorted order, then the array is
reversed (in-place, making it sorted) and a false value is returned.
Otherwise a true value is returned.
So, if you start out with a sorted array, then you can use that as your
first permutation and then call NextPermute* to get the next permutation
to use, until NextPermute* returns a false value (at which point your
array has been returned to its original, sorted order).
So you would use NextPermute() like this:
my @list= sort GetValuesSomehow();
do {
DoSomethingWithPermutation( @list );
} while( NextPermute( @list ) );
or, if your list only contains numbers, you could use NextPermuteNum()
like this:
my @list= sort {$a<=>$b} GetNumbersSomehow();
do {
DoSomethingWithPermutation( @list );
} while( NextPermuteNum( @list ) );
=head3 Notes
The NextPermute* functions each have a prototype specifications of (\@).
This means that they demand that you pass them a single array which they
will receive a reference to.
If you instead have a reference to an array, you'll need to use C<@{ }>
when calling a NextPermute* routine:
} while( NextPermute( @{$av} ) );
(or use one of several other techniques which I will leave the
consideration of as an "exercise" for the more advanced readers
of this manual).
Note that this particular use of a function prototype is one that I am
not completely comfortable with. I am tempted to remove the prototype
and force you to create the reference yourself before/when calling these
functions:
} while( NextPermute( \@list ) ); # Wrong
because
=over 4
=item
It makes it obvious to the reader of the code that a reference to the
array is what is being used by the routine. This makes the reader more
likely to realize/suspect that the array is being modified in-place.
=item
Many/most uses of Perl function prototypes are more trouble than they are
worth. This makes using even the less problematic cases often not a good
idea.
=back
However, I have decided to use a prototype here because:
=item
( run in 1.914 second using v1.01-cache-2.11-cpan-5735350b133 )