Iteration with foreach and for Loops

while loops provide a general way to repeat a block of code—that block will just keep executing until some test is met. The for loop, a second form of loop, is a slightly different approach to the same problem. With for loops, the loop is executed a specific number of times, and then stops. This is sometimes called iteration because the focus is on the specific number of loops as opposed to the more vague “loop until true” that the while provides.

In just about every case, you could write a while loop to do iteration, or you could write a for loop to do the same thing as a while. But some tasks lend themselves better to one form or another, and so we have multiple kinds of loops.

Perl provides two for loops: a foreach that enables a block to be repeated for each element in a list, and a more general-purpose for loop.

foreach

You've already seen foreach as used to iterate over lists and over the keys in a hash. Here are the specifics of how it's used: The foreach loop takes a list as an argument—for example, a range, or a list of keys in a hash—and executes a block of statements for each element in the list. It also takes a temporary scalar variable that gets assigned to each element in the list in turn.

Here's a simple foreach loop that prints the number of the counter five times:

foreach $loop (1 .. 5) {
   print "loop $loop
";
}

Here the range operator .. creates a list of numbers 1 to 5, and the foreach loop works through that list, assigning each number to the $loop variable.

Probably the most common use for foreach loops is for iterating over actual lists, for example, to print out the keys and values of a hash, as you learned yesterday:

foreach $key (sort keys %hashname) {
   print "Key: $key Value: $hashname{$key} 
";
}

You'll note that I haven't initialized the $key variable here (or the $loop variable, earlier). That's because the variable after the foreach and before the list is a local variable to the loop—if it doesn't exist prior to the loop, it'll stop existing after the loop. If it does exist prior to the loop, the foreach will just use it as a temporary variable, and then restore its original value when you're done looping. You can think of the foreach variable as a sort of scratch variable used solely to store elements, which is then thrown away when the loop's done.

One other important thing to note about the $key variable; it does not just contain the value of the current list element, it is the actual list element. If you change the value of $key inside the block, then you will also be changing that list element, and therefore the list (or array or hash) itself. In programmer parlance: the $key variable is passed by reference. Here's a short Perl script that demonstrates this:

#!/usr/local/bin/perl -w

@ones = (1,1,1,1,1);
$switch = 0;

foreach $key (@ones) {
    if (!$switch) {
        $switch = 1;
        $key = 2;
    } else {$switch = 0};
}

print "@ones
";

Initially in this script the @ones array is assigned to (1,1,1,1,1). When the script finishes and the array is printed at the end, the @ones array contains (2 1 2 1 2). The $switch variable alternates between 0 and 1 with each pass of the loop, so that every other list element is changed. But the line inside the block where $key is assigned to 2 is where the list is changed. It's the variable $key that is assigned to 2, but $key refers to the current list element inside @ones, so that list element is changed as well. Even though $key changes every time the loop turns, and then vanishes altogether when the loop is complete, the result of changing it still lingers.

If you want to modify the actual value of $key without also affecting the list it came from, you can always copy it to a temporary variable:

foreach $key (@array) {
   $temp = $key;
   $temp = "blah blah blah";  # will not change the list
   ...
"

for

For a more general-purpose iterative loop that isn't necessarily tied to list elements, you can use a for loop. Perl borrowed the syntax of this loop from the C language, so if you're familiar with that language this will look the same.

The for loop in Perl has four parts:

  • An initializer statement

  • An ending test

  • A change or increment statement

  • The loop block

The for loop looks like this:

for ( init; test; change ) {
   # statements
}

Using these statements, then, the for loop works like this:

  • The first time through, the initializer statement is executed. Often this statement sets a counter such as $i or $j to 0.

  • The test is tested. The test often compares the counter against some value, for example $i < $#array or $i == 0. If the test is false, the loop exits and none of the statements inside the block are executed.

  • If the test is true, the block is executed.

  • After all the statements in the block have executed, the change or increment expression is executed. This statement usually brings the loop one iteration closer to completion, for example, to increment or decrement the counter ($i++).

  • The test is tried again, and again, as the loop repeats.

So, for example, to loop five times you might use a for loop like this:

for ( $i = 1; $i <= 5; $i++) {
   print "loop $i
";
}

The snippet of code produces this output:

loop 1
loop 2
loop 3
loop 4
loop 5

You could, of course, have written this loop as a while:

$i = 1;
while ($i <= 5) {
   print "loop $i
";
   $i++;
}

The two loops would both loop five times, but it might take some searching in the while to figure that out and it takes more lines to do it (or at least it does the way I formatted it here). The for loop puts it all up front—where to start, where to stop, and the steps to take in between. Whether you use a for loop or a while loop depends on the situation and what you feel more comfortable with at the time.

Usually, but not always, the for loop uses a temporary counter variable (commonly called $i or $j) to keep track of the iterations. This is very common, but it isn't required. Depending on the iteration you're doing, you can initialize, test, and change anything you want in the top part of the for. For example, here's a somewhat pointless for loop that creates an array, and then destroys it, backwards, printing the number of remaining and the array itself as it goes:

for (@things = (33,44,55,66); @things > 0; pop @things) {
    print scalar @things, " elements left in @things
";
}

I can't imagine what sort of Perl program would need this kind of loop, and because it iterates over a list it would probably make more sense as a foreach. The idea to grasp here is that as long as you have the three parts: a start point, an end point, and something to step you between the two, you have a for loop.

But wait. You don't even need all three. You can leave off the initialization, the test, the change, or all three, in the top part of the for. You still need to include the semicolons between them, however. So, to create an infinite for loop, you might leave off the test statement:

for ($i = 0; ; $i++) {
   # statements
}

Or just this:

for (;;) {
   # statements
}

The first one initializes the counter and just increments it each time; there's no test so there's no end point. The second doesn't even use a counter or have a test; it just loops. You'll need to do something inside these loops (such as a last) to break out of them when an appropriate condition is met.

Want to use multiple counters? You can do that, too; by separating the counter expressions with commas:

for ($i=0, $j=1; $i < 10, $j < $total; $i++, $j++ ) {
   # statements
}

In this case, the for loop will exit if either one of the tests returns false.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset