Algorithm-Loops

 view release on metacpan or  search on metacpan

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

The same process can be accomplished using a careful and more complex
invocation of map, grep, or foreach.  However, many incorrect ways to
attempt this seem rather seductively appropriate so this function helps
to discourage such (rather common) mistakes.

=head3 Usage

Filter has a prototype specification of (\&@).

This means that it demands that the first argument that you pass to it be
a CODE reference.  After that you can pass a list of as many or as few
values as you like.

For each value in the passed-in list, a copy of the value is placed into
$_ and then your CODE reference is called.  Your subroutine is expected
to modify $_ and this modified value is then placed into the list of
values to be returned by Filter.

If used in a scalar context, Filter returns a single string that is the
result of:

    $string= join "", @results;

Note that no arguments are passed to your subroutine (so don't bother
with @_) and any value C<return>ed by your subroutine is ignored.

Filter's prototype also means that you can use the "map BLOCK"-like
syntax by leaving off the C<sub> keyword if you also leave off the
comma after the block that defines your anonymous subroutine:

        my @copy= Filter sub {s/\s/_/g}, @list;
  # becomes:            v^^^       v   ^
        my @copy= Filter {s/\s/_/g} @list;

Most of our examples will use this shorter syntax.

Note also that by importing Filter via the C<use> statement:

    use Algorithm::Loops qw( Filter );

it gets declared before the rest of our code is compiled so we don't have
to use parentheses when calling it.  We I<can> if we want to, however:

        my @copy= Filter( sub {s/\s/_/g}, @list );

=head3 Note on "Function BLOCK LIST" bugs

Note that in at least some versions of Perl, support for the "Filter
BLOCK ..." syntax is somewhat fragile.  For example:

    ... Filter( {y/aeiou/UAEIO/} @list );

may give you this error:

    Array found where operator expected

which can be fixed by dropping the parentheses:

    ... Filter {y/aeiou/UAEIO/} @list;

So if you need or want to use parentheses when calling Filter, it is best
to also include the C<sub> keyword and the comma:

    #         v <--------- These ---------> v
    ... Filter( sub {y/aeiou/UAEIO/}, @list );
    # require   ^^^ <--- these ---> ^ (sometimes)

so your code will be portable to more versions of Perl.

=head3 Examples

Good code ignores "invisible" characters.  So
instead of just chomp()ing, consider removing
all trailing whitespace:

    my @lines= Filter { s/\s+$// } <IN>;

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



( run in 0.843 second using v1.01-cache-2.11-cpan-39bf76dae61 )