Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the difference between iterating over a file with foreach or while in Perl?

I have a filehandle FILE in Perl, and I want to iterate over all the lines in the file. Is there a difference between the following?

while (<FILE>) {     # do something } 

and

foreach (<FILE>) {     # do something } 
like image 309
Nathan Fellman Avatar asked Feb 25 '09 09:02

Nathan Fellman


People also ask

What is the difference between reading a file with for and with a while?

However, foreach reads each line into a list (not an array) before going through it line by line, whereas while reads one line at a time. As foreach will use more memory and require processing time upfront, it is generally recommended to use while to iterate through lines of a file.

What is the difference between for loop and for each loop in Perl?

There is no difference. From perldoc perlsyn: The foreach keyword is actually a synonym for the for keyword, so you can use foreach for readability or for for brevity.

What is difference between for loop and foreach?

For Loops executes a block of code until an expression returns false while ForEach loop executed a block of code through the items in object collections. For loop can execute with object collections or without any object collections while ForEach loop can execute with object collections only.

What is foreach loop in Perl?

A foreach loop is used to iterate over a list and the variable holds the value of the elements of the list one at a time. It is majorly used when we have a set of data in a list and we want to iterate over the elements of the list instead of iterating over its range.


2 Answers

For most purposes, you probably won't notice a difference. However, foreach reads each line into a list (not an array) before going through it line by line, whereas while reads one line at a time. As foreach will use more memory and require processing time upfront, it is generally recommended to use while to iterate through lines of a file.

EDIT (via Schwern): The foreach loop is equivalent to this:

my @lines = <$fh>; for my $line (@lines) {     ... } 

It's unfortunate that Perl doesn't optimize this special case as it does with the range operator (1..10).

For example, if I read /usr/share/dict/words with a for loop and a while loop and have them sleep when they're done I can use ps to see how much memory the process is consuming. As a control I've included a program that opens the file but does nothing with it.

USER       PID %CPU %MEM      VSZ    RSS   TT  STAT STARTED      TIME COMMAND schwern  73019   0.0  1.6   625552  33688 s000  S     2:47PM   0:00.24 perl -wle open my $fh, shift; for(<$fh>) { 1 } print "Done";  sleep 999 /usr/share/dict/words schwern  73018   0.0  0.1   601096   1236 s000  S     2:46PM   0:00.09 perl -wle open my $fh, shift; while(<$fh>) { 1 } print "Done";  sleep 999 /usr/share/dict/words schwern  73081   0.0  0.1   601096   1168 s000  S     2:55PM   0:00.00 perl -wle open my $fh, shift; print "Done";  sleep 999 /usr/share/dict/words 

The for program is consuming almost 32 megs of real memory (the RSS column) to store the contents of my 2.4 meg /usr/share/dict/words. The while loop only stores one line at a time consuming just 70k for line buffering.

like image 194
Alex Reynolds Avatar answered Sep 29 '22 04:09

Alex Reynolds


In scalar context (i.e. while) <FILE> returns each line in turn.

In list context (i.e. foreach) <FILE> returns a list consisting of each line from the file.

You should use the while construct.

See perlop - I/O Operators for more.

Edit: j_random_hacker rightly says that

while (<FILE>) { … } 

tramples on $_ while foreach does not (foreach localises $_ first). Surely this is the most important behavioural difference!

like image 28
kmkaplan Avatar answered Sep 29 '22 04:09

kmkaplan