in reply to writing two files (different in length) to one output

hmm ... TIMTOWTDI! :)

What about combining eof with seek ?

open ONE, '<' ,'one.txt'; open TWO, '<' ,'two.txt'; my $go=2; while ($go) { my $line1 = <ONE>; my $line2 = <TWO>; chomp $line1,$line2; print "$line1 \t $line2"; $go--, seek ONE,0,0 if eof ONE; $go--, seek TWO,0,0 if eof TWO; }

one.txt has 3, two.txt 5 lines

that's the output

1 1 2 2 3 3 1 4 2 5

HTH! :)

Cheers Rolf
(addicted to the Perl Programming Language and ☆☆☆☆ :)
Je suis Charlie!

Replies are listed 'Best First'.
Re^2: writing two files (different in length) to one output
by Marshall (Canon) on May 28, 2017 at 19:43 UTC
    I really liked your solution! However, I think there is a small problem with the loop conditional. $go gets decremented every time a seek to the beginning of a file is done. This worked fine in your test case, but what if file1 needs to gets "rewound" many times? $go could get decremented a bunch of times before an eof on TWO happens.

    I re-coded with the idea that the loop is over when an EOF has been seen at least once on both files. I don't have any big issue with the use of the comma statement, but since this could be confusing, I expanded that part of the code into 2 discrete statements.

    #!usr/bin/perl use strict; use warnings; open ONE, '<' ,'one.txt' or die "Ooops $!"; open TWO, '<' ,'two.txt' or die "Ooops $!"; my $EOFseenfile1=0; my $EOFseenfile2=0; # Loop finished when EOF has been seen at least once # on both files. while (not $EOFseenfile1 or not $EOFseenfile2) #go until both EOF seen { my $line1 = <ONE>; my $line2 = <TWO>; chomp ($line1, $line2); print "$line1 \t $line2\n"; if (eof ONE) { seek ONE,0,0; $EOFseenfile1++; } if (eof TWO) { seek TWO,0,0; $EOFseenfile2++; } } __END__ file 1 line 1 file 2 line 1 file 1 line 2 file 2 line 2 file 1 line 3 file 2 line 3 file 1 line 1 file 2 line 4 file 1 line 2 file 2 line 5 file 1 line 3 file 2 line 6 file 1 line 1 file 2 line 7 file 1 line 2 file 2 line 8 file 1 has 3 lines file 2 has 8 lines
    "eof" is also nice because you get that status right after reading the last valid line. The next read on that file handle would produce an undefined line which often ends many while() input loops, e.g. while ($line = <IN>){}. By using "eof" instead of an undefined read, no "re-reading" is necessary++, very nice.

    Update:
    Geez, if guess while (not $EOFseenfile1 or not $EOFseenfile2){} could be while (!($EOFseenfile1 and $EOFseenfile2)){}. I don't know why I coded the first version. These two while conditionals are equivalent.

      You are absolutely right! My fault ...:)

      > "eof" is also nice because you get that status right after reading the last valid line.

      Yep, not sure how efficient the implementation is, but rotating over iterators is usually not that much fun...

      I recently stumbled over eof while reading perlfunc for the "Overview scalar vs list context?" thread.

      FWIW, my approach would be something like:

      open ONE, '<' ,'one.txt'; open TWO, '<' ,'two.txt'; my $finished_1, $finished_2; until ( $finished_1 and $finished_2) { my $line1 = <ONE>; my $line2 = <TWO>; chomp $line1, $line2; print "$line1 \t $line2"; ++$finished_1, seek ONE,0,0 if eof ONE; ++$finished_2, seek TWO,0,0 if eof TWO; }
      out (ONE shortened to 2 lines)
      1 1 2 2 1 3 2 4 1 5

      Cheers Rolf
      (addicted to the Perl Programming Language and ☆☆☆☆ :)
      Je suis Charlie!

        Hi Rolf!
        Your code works, but I would make 2 modifications.
        my $finished_1, $finished_2; # should be: my ($finished_1, $finished_2); # list context is needed for the "my" to apply to # both variables. chomp $line1, $line2; # the chomp() does not operate on $line2. # Again, list context is needed... # chomp ($line1, $line2); # but that requires a change in the print # # e.g., print "$line1 \t $line2\n"; # # Of course code could be just: # chomp $line1; #leave $line2 out of it! # My coding preference would be to be symmetrical, # i.e. # chomp ($line1, $line2); # and add the extra $line2 line ending back in # during the print. # # instead of: print "$line1 \t $line2"; # print "$line1 \t $line2\n";
        Yes eof test is much better!
        My first impulse, at first glance was to write a read_circular subroutine. But this winds up being "messy":
        sub read_circular { my $fh = shift; my $line; do { $line = <$fh>; seek ($fh,0,0) if !(defined $line); #restart from beginning }until (defined $line); return $line; }
        Or some such formulation...
        If we have to wait until the read() is undefined, then a "re-read" is necessary. The "eof" status happens right after the last valid line is read. So no "re-reading" is needed. A far superior solution++.

        ...not sure how efficient the implementation is...
        I am quite sure that your code will run very well. I will point out again, that
        ++$finished_1, seek ONE,0,0 if eof ONE; # this is the same as if ( eof ONE) { $finished_1++; #post or pre-increment the same seek ONE,0,0; } # the number of source code lines does not equate # directly into actual "code savings". The more # wordy "if" loop will code into very similar, if # not the exactly the same executing code
        Again, Nice Idea using eof test++.