Your first example is a "C style" loop, as others have already pointed out. I might add that many feel there is usually a more elegant way to do it than a C style loop, thanks to the way foreach works.
Your second example failed because you are counting from zero to size-of-array, rather than zero to last-element-of-array. This is causing you to loop one element past the end of the way. If you're not using warnings and strictures, Perl will just happily let you do it, but your results won't be what you're looking for. For a ".." list constructor to work in this case, you might want
foreach ( 0..@#array ) {...
instead, which constructs a list of numbers from zero to last-element-number-of-@array. The loop iterates over the list of numbers, and $_ can be used as a subscript to @array.
But as you've deduced, there is yet a better way to do it:
foreach ( @array ) {.....
In that case, what you get is the loop iterating over the actual elements of the array. There is no need to read into the array yourself in the loop's block. Instead, $_ becomes an alias for $array[current-loop-iteration]. Any changes you make to $_, in this context, will write through to the current element of @array.
The next tidbit is to understand that foreach and for are synonyms for each other in Perl's internals. Therefore, 'foreach ( @array )' can also be written as 'for ( @array )', and you will get the same results. For most people, myself included, it is usually a better practice to say foreach when you mean it, and for when you mean it, but the fact is that you can say potato and I can say potato (soft A), and Perl considers it the same thing.
The next topic raised in this discussion thread is what happens to $_ in the following example:
foreach ( @first_array ) {
foreach ( @second_array ) {
print "$_\n";
}
}
Specifically, the question was, can the inner loop access the current element of @first_array? No, not as the code is written. Think of $_ as being "my $_", with its own namespace for the current block. That inner loop is its own block, and $_ within that block refers to the current element of @second_array. But outside of the inner loop, either before the inner loop or after it, $_ refers to the outter loop's current element, as long as you're still inside the outter loop. ;) Got it? (Just read that last sentence twice and it will all be ok.)
What you need, if you want to be able to refer back to the current element of the outter loop, from within the inner loop, is one of the following two constructs (Which differ in functionality. I'll describe that later).
foreach my $outter_element ( @outter_array ) {
foreach ( @inner_array ) {
print "$outter_element, $_\n";
}
}
OR
foreach ( @outter_array ) {
my $outter_element = $_;
foreach ( @inner_array ) {
print "$outter_element, $_\n";
}
}
The two above examples function identically as the examples are presented. However, remember that within foreach loops, $_ IS A $array[current_element]. In other words, whatever you do to $_, within the foreach loop, modifies the current iteration's @array element. So in the first example, you can still modify the outter array's current element from within the inner loop. Whereas in the second example, you can only modify the inner array's current element, because in the second example, $outter_element is just a copy of the outter element's value.
That's a mouthful. But it's a very useful distinction to understand.
Also understand that in the case of 'for ( @array )' or 'foreach ( @array )', you don't have a counter, you just have the element itself in $_. If you want a counter, you'll have to establish one explicitly. But unless you explicitly *need* to know how many times you've looped, you can just not even worry about how many times you've looped, and let the script happily do its thing.
Finally, I've seen mention in this thread of the following construct:
print "$_\n" foreach @array;
This is an elegant way of saying:
foreach ( @array ) {
print "$_\n";
}
Use that construct when it makes the code more readable, but leave it alone if it seems to make the code more obscure. It's a style issue. There are perfectly legitimate examples of when each of those constructs might make for cleaner code.
Have fun with loops! ;)
Dave
"If I had my life to do over again, I'd be a plumber." -- Albert Einstein |