At this point, I might as well include the code...

So here it is (minus the POD) and a link to the copy on search.cpan.org.

Most of the routines include improvements over the versions available on PerlMonks. You might also want to check out the example scripts included with the module.

package Algorithm::Loops; # The command "perldoc Algorithm::Loops" will show you the # documentation for this module. You can also seach for # "=head" below to read the unformatted documentation. use strict; BEGIN { # Some still don't have warnings.pm: if( eval { require warnings } ) { warnings->import(); if( eval { require warnings::register; } ) { warnings::register->import(); } } else { # $^W= 1; } } require Exporter; use vars qw( $VERSION @EXPORT_OK ); BEGIN { $VERSION= 1.031_00; @EXPORT_OK= qw( Filter MapCar MapCarE MapCarU MapCarMin NestedLoops NextPermute NextPermuteNum ); { my @nowarn= ( *import, *isa ) } *import= \&Exporter::import; *isa= \&UNIVERSAL::isa; } sub _Type { my( $val )= @_; return ! defined($val) ? "undef" : ref($val) || $val; } sub _Croak { my $depth= 1; my $sub; do { ( $sub= (caller($depth++))[3] ) =~ s/.*:://; } while( $sub =~ /^_/ ); if( eval { require Carp; 1; } && defined &Carp::croak ) { unshift @_, "$sub: "; goto &Carp::croak; } die "$sub: ", @_, ".\n"; } sub Filter(&@) { my( $code, @vals )= @_; isa($code,"CODE") or _Croak( "No code reference given" ); # local( $_ ); # Done by the loop. for( @vals ) { $code->(); } wantarray ? @vals : join "", @vals; } sub MapCarE(&@) { my $sub= shift(@_); isa($sub,"CODE") or _Croak( "No code reference given" ); my $size= -1; for my $av ( @_ ) { isa( $av, "ARRAY" ) or _Croak( "Not an array reference (", _Type($av), ")" ); if( $size < 0 ) { $size= @$av; } elsif( $size != @$av ) { _Croak( "Arrays with different sizes", " ($size and ", 0+@$av, ")" ); } } my @ret; for( my $i= 0; $i < $size; $i++ ) { push @ret, &$sub( map { $_->[$i] } @_ ); } return wantarray ? @ret : \@ret; } sub MapCarMin(&@) { my $sub= shift(@_); isa($sub,"CODE") or _Croak( "No code reference given" ); my $min= -1; for my $av ( @_ ) { isa( $av, "ARRAY" ) or _Croak( "Not an array reference (", _Type($av), ")" ); $min= @$av if $min < 0 || @$av < $min; } my @ret; for( my $i= 0; $i < $min; $i++ ) { push @ret, &$sub( map { $_->[$i] } @_ ); } return wantarray ? @ret : \@ret; } sub MapCarU(&@) { my $sub= shift(@_); isa($sub,"CODE") or _Croak( "No code reference given" ); my $max= 0; for my $av ( @_ ) { isa( $av, "ARRAY" ) or _Croak( "Not an array reference (", _Type($av), ")" ); $max= @$av if $max < @$av; } my @ret; for( my $i= 0; $i < $max; $i++ ) { push @ret, &$sub( map { $_->[$i] } @_ ); } return wantarray ? @ret : \@ret; } sub MapCar(&@) { my $sub= shift(@_); isa($sub,"CODE") or _Croak( "No code reference given" ); my $max= 0; for my $av ( @_ ) { isa( $av, "ARRAY" ) or _Croak( "Not an array reference (", _Type($av), ")" ); $max= @$av if $max < @$av; } my @ret; for( my $i= 0; $i < $max; $i++ ) { push @ret, &$sub( map { $i < @$_ ? $_->[$i] : () } @_ ); # If we assumed Want.pm, we could consider an early return. } return wantarray ? @ret : \@ret; } sub NextPermute(\@) { my( $vals )= @_; my $last= $#{$vals}; return !1 if $last < 1; # Find last item not in reverse-sorted order: my $i= $last-1; $i-- while 0 <= $i && $vals->[$i] ge $vals->[$i+1]; # If complete reverse sort, we are done! if( -1 == $i ) { # Reset to starting/sorted order: @$vals= reverse @$vals; return !1; } # Re-sort the reversely-sorted tail of the list: @{$vals}[$i+1..$last]= reverse @{$vals}[$i+1..$last] if $vals->[$i+1] gt $vals->[$last]; # Find next item that will make us "greater": my $j= $i+1; $j++ while $vals->[$i] ge $vals->[$j]; # Swap: @{$vals}[$i,$j]= @{$vals}[$j,$i]; return 1; } sub NextPermuteNum(\@) { my( $vals )= @_; my $last= $#{$vals}; return !1 if $last < 1; # Find last item not in reverse-sorted order: my $i= $last-1; $i-- while 0 <= $i && $vals->[$i+1] <= $vals->[$i]; # If complete reverse sort, we are done! if( -1 == $i ) { # Reset to starting/sorted order: @$vals= reverse @$vals; return !1; } # Re-sort the reversely-sorted tail of the list: @{$vals}[$i+1..$last]= reverse @{$vals}[$i+1..$last] if $vals->[$last] < $vals->[$i+1]; # Find next item that will make us "greater": my $j= $i+1; $j++ while $vals->[$j] <= $vals->[$i]; # Swap: @{$vals}[$i,$j]= @{$vals}[$j,$i]; return 1; } sub _NL_Args { my $loops= shift(@_); isa( $loops, "ARRAY" ) or _Croak( "First argument must be an array reference,", " not ", _Type($loops) ); my $n= 1; for my $loop ( @$loops ) { if( ! isa( $loop, "ARRAY" ) && ! isa( $loop, "CODE" ) ) { _Croak( "Invalid type for loop $n specification (", _Type($loop), ")" ); } $n++; } my( $opts )= @_; if( isa( $opts, "HASH" ) ) { shift @_; } else { $opts= {}; } my $code; if( 0 == @_ ) { $code= 0; } elsif( 1 != @_ ) { _Croak( "Too many arguments" ); } else { $code= pop @_; isa($code,"CODE") or _Croak( "Expected CODE reference not ", _Type($code) ); } my $when= delete($opts->{OnlyWhen}) || sub { @_ == @$loops }; if( keys %$opts ) { _Croak( "Unrecognized option(s): ", join ' ', keys %$opts ); } return( $loops, $code, $when ); } sub _NL_Iter { my( $loops, $code, $when )= @_; my @list; my $i= -1; my @idx; my @vals= @$loops; return sub { return } if ! @vals; return sub { while( 1 ) { # Prepare to append one more value: if( $i < $#$loops ) { $idx[++$i]= -1; if( isa( $loops->[$i], 'CODE' ) ) { local( $_ )= $list[-1]; $vals[$i]= $loops->[$i]->(@list); } } ## return if $i < 0; # Increment furthest value, chopping if done there: while( @{$vals[$i]} <= ++$idx[$i] ) { pop @list; return if --$i < 0; } $list[$i]= $vals[$i][$idx[$i]]; my $act; $act= !ref($when) ? $when : do { local( $_ )= $list[-1]; $when->(@list); }; return @list if $act; } }; } sub NestedLoops { my( $loops, $code, $when )= _NL_Args( @_ ); my $iter= _NL_Iter( $loops, $code, $when ); if( ! $code ) { if( ! defined wantarray ) { _Croak( "Useless in void context", " when no code given" ); } return $iter; } my @ret; my @list; while( @list= $iter->() ) { @list= $code->( @list ); if( wantarray ) { push @ret, @list; } else { $ret[0] += @list; } } return wantarray ? @ret : ( $ret[0] || 0 ); } "Filtering should not be straining"; __END__ POD removed from this copy.

I'd like to thank the Sharp Zaurus for making this module possible.

                - tye

In reply to Re: Algorithm::Loops released (code) by tye
in thread Algorithm::Loops released by tye

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.