Algorithm-Loops

 view release on metacpan or  search on metacpan

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

or

    my $line= Filter { s/\s+$// } scalar <IN>;

[ Note that Filter can be used in a scalar
context but always puts its arguments in a
list context.  So we need to use C<scalar> or
something similar if we want to read only one
line at a time from C<IN> above. ]

Want to sort strings that contain mixtures of
letters and natural numbers (non-negative
integers) both alphabetically and numerically
at the same time?  This simple way to do a
"natural" sort is also one of the fastest.
Great for sorting version numbers, file names,
etc.:

    my @sorted= Filter {
        s#\d{2}(\d+)#\1#g
    } sort Filter {
        s#(\d+)# sprintf "%02d%s", length($1), $1 #g
    } @data;

[ Note that at least some versions of Perl have a bug that breaks C<sort>
if you write C<sub {> as part of building the list of items to be sorted
but you don't provide a comparison routine.  This bug means we can't
write the previous code as:

    my @sorted= Filter {
        s#\d{2}(\d+)#\1#g
    } sort Filter sub {
        s#(\d+)# sprintf "%02d%s", length($1), $1 #g
    }, @data;

because it will produce the following error:

    Undefined subroutine in sort

in some versions of Perl.  Some versions of Perl may even require you
to write it like this:

    my @sorted= Filter {
        s#\d{2}(\d+)#\1#g
    } sort &Filter( sub {
        s#(\d+)# sprintf "%02d%s", length($1), $1 #g
    }, @data );

Which is how I wrote it in ex/NaturalSort.plx. ]

Need to sort names?  Then you'll probably want to ignore letter case and
certain punctuation marks while still preserving both:

    my @compare= Filter {tr/A-Z'.,"()/a-z/d} @names;
    my @indices= sort {$compare[$a] cmp $compare[$b]} 0..$#names;
    @names= @names[@indices];

You can also roll your own simple HTML templating:

    print Filter {
        s/%(\w*)%/expand($1)/g
    }   $cgi->...,
        ...
        $cgi->...;

Note that it also also works correctly if you change how you output your
    HTML and accidentally switch from list to scalar context:

    my $html= '';
    ...
    $html .= Filter {
        s/%(\w*)%/expand($1)/g
    }   $cgi->...,
        ...
        $cgi->...;

=head3 Motivation

A reasonable use of map is:

    @copy= map {lc} @list;

which sets @copy to be a copy of @list but with all of the elements
converted to lower case.  But it is too easy to think that that could
also be done like this:

    @copy= map {tr/A-Z/a-z/} @list;  # Wrong

The reason why these aren't the same is similar to why we write:

    $str= lc $str;

not

    lc $str;  # Useless use of 'lc' in void context

and we write:

    $str =~ tr/A-Z/a-z/;

not

    $new= ( $old =~ tr/A-Z/a-z/ );  # Wrong

That is, many things (such as lc) return a modified copy of what they are
given, but a few things (such as tr///, s///, chop, and chomp) modify
what they are given I<in-place>.

This distinction is so common that we have several ways of switching
between the two forms.  For example:

        $two= $one + $other;
  # vs.
        $one += $other;

or

        $two= substr($one,0,4);
  # vs.
        substr($one,4)= '';

I've even heard talk of adding some syntax to Perl to allow you to make
things like C<lc> become reflexive, similar to how += is the reflexive
form of +.

But while many non-reflexive Perl operations have reflexive counterparts,
there are a few reflexive Perl operations that don't really have
non-reflexive counterparts: s///, tr///, chop, chomp.

You can write:

        my $line= <STDIN>;



( run in 0.740 second using v1.01-cache-2.11-cpan-5b529ec07f3 )