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 )