http://www.perlmonks.org?node_id=870359


in reply to Re: Reading two text files parallelly...
in thread Reading two text files parallelly...

while (my $test1 = <$fh1>, my $test2 = <$fh2>) This is "comma operator". The "true" or "false" of the "while" only depends upon the state of $test2. The comma operator is a way to combine two what normally would be completely separate statements "together". This should be used only with extreme caution.

A common use for this is in user prompting loops. Putting the prompt together with the ending condition solves the problem of "how to get the loop started" and at the same time puts the condition that is going to stop the loop right up there where it belongs - right in the statement that runs the loop - not buried somewhere in the "guts".

Here is an example. We are asking about part numbers. The user prompt is clear. What stops the loop is clear (q,Q,QuIT, etc) and it is right there where it is supposed to be, in the controlling loop statement. In the "guts" of the loop there will be many error messages like "hey, dummy a part number needs 10 digits" or whatever, followed by a "next;" statement - that restarts the loop and re-prompts the user.

while ( (print "Enter Part No and Qty: "), (my $line=<STDIN>) !~ /^\s*q(uit)?\s*$/i ) {...}
Some would argue that it is better to move the ending condition into the loop and make it the first statement. Well ok thats one way. In that case we have:
last if $line !~/^\s*q(uit)?\s*$/i;
I would argue against that as "do forever" loops should be reserved for servers, GUI event loops and such.

In any event, the OP doesn't appear to be in need of such things.

Replies are listed 'Best First'.
Re^3: Reading two text files parallelly...
by Hugmeir (Sexton) on Nov 09, 2010 at 19:15 UTC
    This is "comma operator". The "true" or "false" of the "while" only depends upon the state of $test2.

    Oh, completely missed that.. All my tests had the second file longer than the first. ++ for the explanation! If I may take another moment of your time, I tried fixing that code from before, although now I think that I'm using one of those endless loops you adviced against:

    while (my ($test1, $test2) = (scalar <$fh1>, scalar <$fh2>)) { last unless defined $test1 or defined $test2; ... }
    I figure that the simplest fixes (for me, that is: Feel free to kick me on the right path) would be to either use the defined-or on the results of the readlines, replacing the undefs with the empty list, or move everything into a sub.

    ..actually, rather than talk about it:

    defined-or'ing

    while ( my $test1, $test2 ) = (scalar <$fh1> // (), scalar <$fh2> // ( +) ) { ... }
    sub'd
    sub read_double_file { my ($fh1, $fh2) = @_; my ($line_file_1, $line_file_2) = (scalar <$fh1>, scalar <$fh2>); (defined $line_file_1 or defined $line_file_2) ? ($line_file_1 //= +'', $line_file_2 //= '') : (); } while ( my ($line_from_1, $line_from_2) = read_double_file($fh1, $fh2) + ) { ... }
    Is there a better approach? (For whatever reason, trying to solve this has been quite fun -- I'm even thinking about meddling with objects, just so I don't have to pass the filehandles over and over to the subs) Are the attempts so far horribly, terribly wrong?
      Sounds like the main problem is to get very clear about what you want this program to do. If you want to just stop when both files are over, or when lines run out of one of them, another possibility is below. The while() takes an expression that evaluates to true/false. Nothing wrong with have more than one condition in an "and" statement. You can use "or" if you want. I don't see the need for anything fancy - try to keep it as easy to understand as possible.
      #!/usr/bin/perl -w use strict; open (my $fh1, '<', "testa.txt") or die "cannot open testa"; open (my $fh2, '<', "testb.txt") or die "cannot open testb"; while ( defined (my $test1 = <$fh1>) and defined (my $test2 = <$fh2>) ) { print "both defined\n"; }