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

I have the following snippet of code that for the most part works correctly. Until it gets to the part where it subtracts. Then who knows what is happening. Here is the code:
### Here is a sample of the input file line: 563,U016228,4,CEL30.0-6/38,Kg,1217,0,1742,0,0,81.5,2070,Kg,trfJPL,81,1 +/2,01/15/02,118,30,tn,01/15/02,01/15/02 #### Code starts here ### foreach $line(<FILE>) { chomp($line); $line =~ s/"//g; $line =~ s/ //g; @record = split(/,/,$line); #### The custhash is created from an index file. if(!defined $custhash{$record[0]}[0]) { print "$line\n"; next; } $salesman = $custhash{$record[0]}[0]; $custnum = $record[0]; #### The next 2 lines are not producing the expected result! $hashlist{$salesman}{$custnum}[6] += $record[5]; $hashlist{$salesman}{$custnum}[6] -= $record[7]; ##### These 3 lines I used for debug and the results are ??? $orders += $record[5]; $shipments += $record[7]; $openorders += $hashlist{$salesman}{$custnum}[6]; #on hand inventory $hashlist{$salesman}{$custnum}[8] += $record[6]; @duedate = split(/\//,$record[16]); ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime; if(($duedate[0] == ($mon+1)) && ($duedate[2] == ($year-100))) { #due this month $hashlist{$salesman}{$custnum}[7] += $record[9]; } } close (FILE); #### These lines are accurate data... $calcorders = $orders - $shipments; print "mk_sales1.pl orders=$orders shipments=$shipments\n"; print "mk_sales1.pl open=$openorders calc open=$calcorders\n"; exit;
Here is an example of the output:
mk_sales1.pl orders=4555921.98401899 shipments=1018457.10569 +208 mk_sales1.pl open=162276886.110807 calc open=3537464.87832691
The expected result is orders - shipments = open. However you get orders - shipment = calcopen. And calcopen should = open. In case you are wondering calcopen is accurate.. Hmmmm ???

Replies are listed 'Best First'.
(Ovid) Re: Problem subtracting in Perl
by Ovid (Cardinal) on Jan 18, 2002 at 00:42 UTC

    Off the top of my head, I don't see your problem right away. This could be an issue with the data or an issue with the code. The interesting thing, though, is that problems like this can often be spotted quickly if the code is developed well. Let's take a look at what you have (I've cleaned up the formatting to clarify scope:

    01: foreach $line(<FILE>) 02: { 03: chomp($line); 04: $line =~ s/"| //g; 05: @record = split(/,/,$line); 06: 07: #### The custhash is created from an index file. 08: if(!defined $custhash{$record[0]}[0]) 09: { 10: print "$line\n"; 11: next; 12: } 13: 14: $salesman = $custhash{$record[0]}[0]; 15: $custnum = $record[0]; 16: 17: #### The next 2 lines are not producing the expected result! 18: $hashlist{$salesman}{$custnum}[6] += $record[5]; 19: $hashlist{$salesman}{$custnum}[6] -= $record[7]; 20: 21: ##### These 3 lines I used for debug and the results are ??? 22: $orders += $record[5]; 23: $shipments += $record[7]; 24: $openorders += $hashlist{$salesman}{$custnum}[6]; 25: 26: #on hand inventory 27: $hashlist{$salesman}{$custnum}[8] += $record[6]; 28: 29: @duedate = split(/\//,$record[16]); 30: ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtim +e; 31: 32: if(($duedate[0] == ($mon+1)) && ($duedate[2] == ($year-100))) 33: { 34: #due this month 35: $hashlist{$salesman}{$custnum}[7] += $record[9]; 36: } 37: } 38: close (FILE);

    Line 4: why are we substituting out quote marks? If they're in your incoming data, this suggests that you might have embedded commas. You're better off with a module like Text::CSV_XS to handle CSV files. If you have a lot of files like this, you can use my CSV Database Validation code to check their integrity.

    Line 8: what is $record[0]? It turns out that it's actually $custnum, as defined on line 15. Move line 15 above line 8 and use that variable. Your code will be more self-documenting. Further, I see that you didn't check to if the customer number exists in the hash. If it doesn't, do you want to autovivify this entry?

    Lines 18 and 19: these are your problem. However, I have no idea what that data really is. Part of the problem stems from your assignment on line 5: @record = split(/,/,$line);. You might want to consider assigning to individual named scalars (or to a hash) so that you have have self-documenting code. Just a bunch of numeric indices gives the programmer no clue as to what is going on. Further, since you are not validating any of the data, how can you tell if you have any data corruption issues?

    The last point is the obvious one: you're not using strict and I suspect you are not using warnings, either. Because you're not using strict, it's very easy for all sorts of nasty bugs to slip unnoticed in your code. Further, since you aren't predeclaring your variables with my, this means that they are global and you may have scoping issues that could trip you up. Is it possible that this code is called more than once and you have some leftover data creeping in?

    Cheers,
    Ovid

    Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

Re: Problem subtracting in Perl
by no_slogan (Deacon) on Jan 18, 2002 at 00:30 UTC

    I'm guessing your data file has multiple lines with the same $salesman and $custnum. When you hit the second one, the "$openorders +=" line double-counts the open orders from the first. It's probably better to calculate the open orders after you've loaded all the records, instead of trying to update it as you go along.

    As a stylistic note, this is hard to understand:

    $hashlist{$salesman}{$custnum}[6]

    And it would probably be better written like this:

    $hashlist{$salesman}{$custnum}{open_orders}

    Or this:

    use constant OPEN_ORDERS => 6; # at top of code $hashlist{$salesman}{$custnum}[OPEN_ORDERS]
Re: Problem subtracting in Perl
by YuckFoo (Abbot) on Jan 18, 2002 at 01:17 UTC
    A better solution is just to make the same adjustments to $openorders that you do to $hash list.

    $openorders += $record[5] - $record[7];

    Yuckfoo

      That is exactly what I did and the subtraction now works. Thanks a million.
Re: Problem subtracting in Perl
by YuckFoo (Abbot) on Jan 18, 2002 at 00:46 UTC
    diakonos,

    If you process two records with the same $salesman and $custnum, the $hashlist amount is getting added to $openorders twice. To fix this, subtract current $hashlist amount from $openorders, adjust the $hashlist amount, then add it back to $openorders. Hope this makes sense,

    YuckFoo

    #### Add this line to fix ??? $openorders -= $hashlist{$salesman}{$custnum}[6]; $hashlist{$salesman}{$custnum}[6] += $record[5]; $hashlist{$salesman}{$custnum}[6] -= $record[7]; ##### These 3 lines I used for debug and the results are ??? $orders += $record[5]; $shipments += $record[7]; $openorders += $hashlist{$salesman}{$custnum}[6];
      Absolutely, I will give it a shot. Thanks. Doug
Re: Problem subtracting in Perl
by diakonos (Hermit) on Jan 18, 2002 at 00:18 UTC
    Also we found the problem first after about 60 lines of data. As more lines of data are input the worse the problem gets. The above sample is from 6000 lines of data.