Developer Forums | About Us | Site Map


Useful Lists

Web Host
site hosted by netplex

Online Manuals

Road to better programming: Chapter 4. Functional programming
By Teodor Zlatanov - 2004-02-23 Page:  1 2 3 4 5 6

The grep() function

For anyone who has used UNIX, the grep() function is simple to learn and use. It acts just like the grep utility -- elements that satisfy a test pass through, while everything else gets dropped.

The syntax of grep() is just like map(). A block or an expression can be passed, and $_ is aliased to the current element under examination. It is not a good idea to modify elements of the list passed to grep(). That's what map() is for. Use grep() to grep, and map() to map. The only exception to this rule is if you must create temporary hash fields or array entries while sorting, but make sure you remove them afterwards.

Listing 5. How grep() works

grep {$_ > 1} @p;                       # only accept numbers more than 1
grep {$_++} @p;                         # please don't do this
grep /hi/,@p;                           # only accept matching elements
grep !/hi/,@p;                          # do not accept matching elements

It can be very convenient to use grep() for quick filtering, but remember that a foreach() loop may be faster under some circumstances. When in doubt, benchmark.

Listing 6. Using grep() to filter out odd numbers

my @list = (1, 2, 3, 'hi');
my @results;
# the procedural approach
foreach (@list)
 push @results, $_
  unless $_%2;
# using grep - FP approach
@results = grep { !($_ % 2) } @list;

Here is another example. Say we need to look in a directory and retrieve all the file names from it:

Listing 7. Using grep() to get all the filenames in a directory

opendir(DIR, ".") || die "can't opendir: $!"; # get the directory handle
my @f = grep { /^[^\.]/ && -f } readdir(DIR); # filter only files into @f

Line 1 of Listing 7 just opens the current directory, or exits the program with the appropriate notice.

Line 2 invokes the readdir() function, which returns a list of filenames, and runs a grep() that filters out hidden files (filenames must not begin with a "." character) and non-file objects such as directories.

In two lines we do as much work as four or five lines of a foreach() loop might do. Don't forget to comment such tight code; the short comments shown are not sufficient for production code. Sometimes, grep() is used in scalar context (for instance, to test if Perl interpreters are running [the Proc::ProcessTable module is from CPAN]):

Listing 8. Using grep() to get all the Perl processes running

use Proc::ProcessTable;                 # get this module from CPAN
use strict;
my $table = new Proc::ProcessTable;
my @procs;
if (@procs = grep { defined $_->cmndline && 
                            $_->cmndline =~ /^perl/ } 
 print $_->pid, "\n" foreach @procs;
 print "No Perl interpreters seem to be running.\n";

Here, we simultaneously assign the return from grep() to the @procs array, and we test to see if it contained any elements at all. If there were no elements matching the pattern, we print a message to that effect. The same code with a foreach() loop would probably take five or six lines. In case it hasn't been said enough, code like Listing 8 should be commented well enough that someone else could look at it and immediately know the intent and effect of that code. It's no use writing production code if you are the only one who will ever be able to read it.

View Road to better programming: Chapter 4. Functional programming Discussion

Page:  1 2 3 4 5 6 Next Page: Sorting with map: the Schwartzian and Guttman-Rosler transforms

First published by IBM developerWorks

Copyright 2004-2023 All rights reserved.
Article copyright and all rights retained by the author.