Reputation: 445
I am having an undesired interaction with a foreach
loop and a while
that I don't quite understand. I have a normal for
loop, and then a foreach
loop going through an array. I create a string (representing a file name) with both and then open the file and read it.
The code I use is here:
@array=(1,2);
for($y=0;$y<2;$y++)
{
foreach(@array)
{
print "@array\n";
$name="/Users/jorge/$_\_vs_$y\.txt";
print "$name\n";
open(INFILE,"$name") or die "Can't open files!\n";
while(<INFILE>)
{
$line=$_;
}
}
}
and the output is:
array: 1 2
/Users/jorge/1_vs_0.txt
array: 2
/Users/jorge/2_vs_0.txt
array:
/Users/jorge/_vs_1.txt
Seems that somehow the while loop is shortening my array, if I remove the:
while(<INFILE>)
it works as intented, also if I change the foreach too:
foreach $tmp (@array)
and use $tmp instead of $_, it also works as intended, the output looks like this:
array: 1 2
/Users/jorge/1_vs_0.txt
array: 1 2
/Users/jorge/2_vs_0.txt
array: 1 2
/Users/jorge/1_vs_1.txt
array: 1 2
/Users/jorge/2_vs_1.txt
array: 1 2
/Users/jorge/1_vs_2.txt
Upvotes: 0
Views: 184
Reputation: 95385
You're using $_
as the loop control variable on two nested loops. Instead, you should give each loop its own variable.
Not only is the inner loop changing the value of the control variable for the outer loop, but it's also changing the actual array being looped over. That's because the loop control variable in Perl's for
/foreach
aliases the elements of the array, so when the <INFILE>
construct reads a line into $_
, it overwrites the current element of @array
with that line. When the while
loop finishes reading the file, $_
comes out of the last <INFILE>
as undefined, which means the most-recently processed element of @array
will always be undefined when you get back to the top of the foreach
loop.
You should also be declaring your variables with my
, using a lexical scalar instead of a bareword as a file handle, and using the the three-argument version of open
, so I've made those changes below as well. But the solution to your shrinking-array problem is just the use of an explicit variable instead of the default $_
for at least one of the two loops.
my @array = (1, 2);
for (my $y = 0; $y < 2; $y++)
{
foreach my $x (@array) # using $x instead of $_
{
print "@array\n";
my $name = "/Users/jorge/${x}_vs_$y.txt";
print "$name\n";
open my $infile, '<', $name or die "$0: can't open file '$name': $!\n";
while (my $line = <$infile>) # using $line instead of $_
{
# do something with $line here
}
}
}
Upvotes: 3
Reputation: 50677
Your while loop overwrites content of array as it uses $_
which is aliased to @array
elements.
It is best to use lexical (my) variable when reading file using while
,
while (my $line = <INFILE>) {
# ..
}
Upvotes: 1