Algorithm-Loops

 view release on metacpan or  search on metacpan

lib/Algorithm/Loops.pm  view on Meta::CPAN

    12: tool

Most permutation generators would have listed each of those twice
(thinking that swapping an "o" with another "o" made a new permutation). 
Or consider:

    > perl ex/Permute.plx noon
    1: nnoo
    2: nono
    3: noon
    4: onno
    5: onon
    6: oonn

Most permutation generators would have listed each of those B<four>
times.

Note that using a hash to eliminate duplicates would require a hash table
big enough to hold all of the (unique) permutations and so would defeat
the purpose of iterating.  NextPermute* does not use a hash to avoid
duplicates.

=item Generated in sorted order

If you were to run code like:


    my @list= sort GetValuesSomehow();
    do {
        print join('',@lista, $/);
    } while(  NextPermute( @list )  );

then the lines output would be sorted (assuming none of the values in
@list contained newlines.  This may be convenient in some corcumstances.

That is, the permutations are generated in sorted order.  The first
permutations have the lowest values at the front of the list.  As you
iterate, larger values are shifted to be in front of smaller values,
starting at the back of the list.  So the value at the very front of the
list will change the fewest times (once for each unique value in the
list), while the value at the very end of the list changes between most
iterations.

=item Fast

If you don't have to deal with duplicate values, then Algorithm::Permute
provides some routines written in C (which makes them harder to install
but about twice as fast to run as the NextPermute* routines) that you can
use.

Algorithm::Permute also includes some fun benchmarks comparing different
Perl ways of finding permutations.  I found NextPermute to be faster than
any of the routines included in those benchmarks except for the ones
written in C that I mentioned above.  Though none of the benchmarked
routines deal with duplicates.

=back

=head3 Notes

Note that NextPermute() considers two values (say $x and $y) to be
duplicates if (and only if) C<$x eq $y>.

NextPermuteNum() considers $x and $y to be duplicates if C<$x == $y>.

If you have a list of floating point numbers to permute, you might want
to use NextPermute() [instead of NextPermuteNum()] as it is easy to end
up with $x and $y that both display the same (say as "0.1") but are
B<just barely> not equal numerically.  Thus $x and $y would I<look> equal
and it would be true that C<$x eq $y> but also true that C<$x != $y>.  So
NextPermute() would consider them to be duplicates but NextPermuteNum()
would not.

For example, $x could be slightly more than 1/10, likely about
0.1000000000000000056, while $y is slightly more at about
0.0999999999999999917 (both of which will be displayed as "0.1" by Perl
and be considered C<eq> (on most platforms):

    > perl -w -Mstrict
    my $x= 0.1000000000000000056;
    my $y= 0.0999999999999999917;
    print "x=$x\ny=$y\n";
    print "are eq\n"   if  $x eq $y;
    print "are ==\n"   if  $x == $y;
    print "are !=\n"   if  $x != $y;
    <EOF>
    x=0.1
    y=0.1
    are eq
    are !=

=head2 NestedLoops

=head3 Introduction

Makes it easy to simulate loops nested to an arbitrary depth.

It is easy to write code like:

    for my $a (  0..$N  ) {
     for my $b (  $a+1..$N  ) {
      for my $c (  $b+1..$N  ) {
          Stuff( $a, $b, $c );
      }
     }
    }

But what if you want the user to tell you how many loops to nest
together?  The above code can be replaced with:

    use Algorithm::Loops qw( NestedLoops );

    my $depth= 3;
    NestedLoops(
        [   [ 0..$N ],
            ( sub { [$_+1..$N] } ) x ($depth-1),
        ],
        \&Stuff,
    );

Then you only have to change $depth to 4 to get the same results as:

    for my $a (  0..$N  ) {
     for my $b (  $a+1..$N  ) {
      for my $c (  $b+1..$N  ) {
       for my $d (  $c+1..$N  ) {
          Stuff( $a, $b, $c, $d );
       }



( run in 0.634 second using v1.01-cache-2.11-cpan-483215c6ad5 )