Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

hello guys, i have a hard time looking @ what's wrong with this script.
is it really right to open two files simultaneously and assign variables?
in temp.txt(output), every value of $check1 (rep. by 300)in every line is the same as the value of $check1 on the first line of file1.txt, like...
222-3344,joe,300,200,100,increase
222-3344,joe,300,150,150,increase
222-3344,joe,300,550,250,decrease

here's the my kiddy script:

#!/usr/bin/perl -w #file1 format: name|phone|check amount this mo. #file2 format: name|phone|check amount last mo. open(F1,"file1.txt") || die "cannot open $infilename for reading: $!"; open(F2,"file2.txt") || die "cannot open $infilename for reading: $!"; open(F3,">temp.txt") || die "cannot create $outfilename: $!"; while (<F1>) { ($name,$phone,$check1) = split(/\|/); while (<F2>) { ($name,$phone,$check2) = split(/\|/); $change = $check1 - $check2; if ($check2 > $check1) { $stat = "decrease"; } else { $stat = "increase"; } $_ = join ',', ("$phone","$name","$check1","$check2","$change","$stat" +); print F3 "$_\n"; } } close (F1); close (F2); close (F3);

Edited 2002-04-04 by mirod: changed title

Replies are listed 'Best First'.
Re: need help with a bug
by dws (Chancellor) on Apr 03, 2002 at 20:16 UTC
    First, it really, really helps readability to indent your code. It's hard to see loops when they're flattened out.

    Second, it really, really helps to state your problem clearly.

    in temp.txt(output), every value of $check1 (rep. by 300)in every line is the same as the value of $check1 on the first line of file1.txt, like...
    doesn't tell me what you expect to have happen (well, it sort of does, but not unambiguously), and it doesn't tell me what symptoms you're seeing.

    What you have set up is a loop to read F2 inside of a loop to read F1. That is, you read one record from F1, then all records from F2. If there's a second record in F1, you won't read any records from F2 unless you rewind it (seek back to the beginning of the file) first.

    Another problem is that a trailing newline is retained in both $check1 and $check2, which is going to screw up the records you're printing. To get rid of them, use chomp(), as in

    while ( <F1> ) { chomp; ... split ...
Re: need help with a bug
by Anonymous Monk on Apr 03, 2002 at 20:51 UTC
    ok, my bad. here's more info...
    file1.txt contents:
    joe|523-3452|300
    mike|624-3850|500
    john|327-3958|100

    file2.txt contents:
    joe|523-3452|200
    mike|624-3850|400
    john|327-3958|200

    temp.txt should then have:
    523-3452|joe|300|200|100|increased
    624-3850|mike|500|400|100|increased
    327-3958|john|100|200|100|decreased


    now, my problem is that temp.txt is showing
    523-3452|joe|300|200|100|increased
    624-3850|mike|300|400|100|increased
    327-3958|john|300|200|100|decreased

    ***notice the third field became all 300
      I re-read your code and saw an additional problem:

      When you read F2 and split the fields, you're overwriting some of the variables that you just got from splitting a record in F1. And, as a consequence of reading all of F2 after reading the first record from F1, you're doing all of your calculations based on the first records in F1.

      I don't think this is what you want to do.

      If you are absolutely sure that the number and order of records will never change, then remove the inner while, so that you're reading a single record from F2 in lock-step with records from F1.

      If you can't guarantee that the order or number of records won't change, read each file into an in-memory hash, do the balance math in-memory, and then write the result.

      And consider walking through your code line-by-line with a pencil and paper (or with a debugger). It'll help your ability to visualize logic.

      #!/usr/local/bin/perl -w use strict; open(F1,"file1.txt") || die $!; open(F2,"file2.txt") || die $!; open(F3,">temp.txt") || die $!; while(1) { my $line1 = <F1>; chomp($line1); my ($name1,$phone1,$check1) = split(/\|/,$line1); my $line2 = <F2>; chomp($line2); my ($name2,$phone2,$check2) = split(/\|/,$line2); print F3 "$phone1,$name1,$check1,$check2," . ($check1-check2) . ',' +. ($check2 > $check1 ? 'decrease' : 'increase') . "\n"; last if eof; } close (F1); close (F2); close (F3);
      results in:
      523-3452,joe,300,200,100,increase 624-3850,mike,500,400,100,increase 327-3958,john,100,200,-100,decrease
      Not very robust. Fails gracelessly if F2 is longer than F1. If the files will be short, consider slurping 'em both into arrays. If you're guaranteed unique combinations of names and phone numbers, consider using them as the keys to a hash whose values are a list or hashref of the check values, so as to remove dependency on the lists being in the same order.