Item 12: Use foreach , map and grep as appropriate.
In Perl, there are several different ways of iterating over elements in a list.
There is a strong tendency among Perl programmers to avoid using a for loop and subscripts when iterating through a list. Loops using subscripts tend to be slower than loops that don't, because subscripts take a significant amount of time for Perl to evaluate. In addition, subscripts can be used only on named arrays.
Most programmers use foreach , map , or grep instead. The capabilities of foreach , map , and grep overlap somewhat, but each is designed for a primary purpose. These constructs are easy to abuseyou can write pretty much any kind of loop with any one of thembut doing so can confuse you and anyone else who visits your code in the future. You should use them appropriately.
Use foreach to iterate read-only over each element of a list
If all you want to do is to cycle over the elements in a list, use foreach :
Remember that foreach uses $_ as a control variable by default if none is specified. Also, you can always use the shorter keyword for instead of foreach Perl knows what you mean.
Use map to create a list based on the contents of another list
If you want to create a transformed copy of a list, use map :
The "transform" expression or block is evaluated in a list context. Sometimes it can be useful to return an empty list or a list of more than one element. Using a match operator inside map can be elegant:
Use m// and memory inside map to capture a list of matching substrings.
For efficiency, $_ is actually an alias for the current element in the iteration. If you modify $_ within the transform expression of a map , you are modifying the list that is being mapped. This is generally considered to be bad style, and, who knows, you may even wind up confusing yourself this way. If you want to modify the contents of a list, use foreach (see below).
You should also make sure that map is returning a sensible valuedon't use map as just a control structure:
map should return a sensible value.
map should not modify its arguments.
If you must use tr/// , s/// or something similar inside map , use a my variable to avoid changes to $_ :
Avoid changes to $_ by using a my variable inside map .
For more examples using map , see Item 14 and Item 60.
Use foreach to modify elements of a list
If you actually want to modify the elements in a list, use foreach . As with map (and also grep ), the control variable is an alias for the current element in the iteration. Modifying the control variable modifies that element.
Use grep to select elements in a list
The grep operator has a particular purpose, which is to select or count elements in a list. You wouldn't know this, though, looking at some of the more creative abuses of grep , which usually originate with programmers who feel that a foreach loop isn't quite as cool as a grep . Hopefully, as you try to write Effective Perl, you will stay closer to the straight and narrow.
Here's a conventional use of grep in a list context:
By the way, the "selection" expression or block argument to grep is evaluated in a scalar context, unlike map 's transform expression. This will rarely make a difference, but it's nice to know.
In a scalar context, grep returns a count of the selected elements rather than the elements themselves .