M. Ilyas Hassan <[EMAIL PROTECTED]> wrote:

: The input file is a flat file (.txt) parsed by "~" with 40
: columns. Columns 2-40 has numbers (all integers, +ve and -ve
: numbers). Column 0 has items in alphanumeric and column 1 has
: labels in text. I would like to find the minimum value for
: numbers in columns 2-40 and write out an output in the form of
: a flat file with 2 columns (col. 0 = item, col. 1 =min value).

    That's 41 columns (0 - 40). 40 columns would be numbered
0 - 39.


: Please see the code I wrote. I does NOT work. Thanks for your
: input and help,

    Always begin your code with these modules. They will help you
to use better programming habits.
    
use strict;
use warnings;


: $i=0;

    Too early. Declare your variables when you use them.


: open INV_RPT, "$_inventory_rpt" or die "Can't open file handler";
: open (INV_RPT_MIN, ">$_inventory_rpt_min");

    $_inventory_rpt and $_inventory_rpt_min have not been defined.


    The first 'open' checks for errors and the second does not.
Why? Be consistent. If you do error checking the first time, do
it the last and every time in between.

    As long as you use perl you will be opening files. Create a
macro for opening files in your code editor. Try to use the same
open idiom each time. Including the $! variable will help you
track down where errors came from. Here's mine.

my $file = '';
open FH, $file or die qq(Cannot open "$file": $!);

close FH;

    Whatever you choose, use the same thing for each 'open'
statement.


: {
:    chop($Ctmp1);
:    @Ctmp2=split(/~/,$Ctmp1);
:    $items{$Ctmp2[0]}=$Ctmp2[0];
: }

    Too early. $Ctmp1 (horrible name for a variable) has not been
defined yet. The hash doesn't hold what you expect. Learn how to
test.

use Data::Dumper 'Dumper';

{
        chop($temp);
        @fields=split(/~/,$temp);
        $items{$fields[0]}=$fields[0];
}
print Dumper \%items;

__END__

I get:

$VAR1 = {
          '' => undef
        };

   So %items has one key with an undefined value. I am not sure
what you intended to do here, but that wasn't it.


: foreach $item (keys %items)
: {

    The hash has one element. We can skip the loop and just write
this. That doesn't look right, does it?
    
my $item = '';


:   while($Ctmp1 = <INV_RPT>)
:    {

    Under strict, that would be written like this. (Read perlfunc
'my') I used $record instead of $Ctmp1 because it is more
descriptive of what the variable holds. Use meaningful variable
names.

    while( my $record = <INV_RPT> )
    {


:     chop($Ctmp1);

    "chop" is deprecated. Throw away whatever tool (book,
tutorial, outdated program, etc,) you are using to learn perl. Go
to learn.perl.org for books and online support for writing good
perl scripts.

        chomp $record;


:     @Ctmp2=split(/~/,$Ctmp1);

    @Ctmp2 as used here has file scope. Let's scope it to this
code block  (using 'my') and let's use a meaningful name for it.

                my @fields = split /~/, $line;

:     $START_MIN{$ctmp2[0]}=$ctmp2[2];

    Why does this hash (%START_MIN) use all caps for the the
variable name? Other variables are mixed case (which I personally
despise). What is so special about this hash that it should
deserve all caps?

    According to your description we are attempting to find the
minimum value in this array. We can do that by importing a
function from List::Util. To import this function we need to "use"
this module (at the beginning of the script). The function we need
is named 'min'.

use List::Util 'min';


:     for $i (0..40) {

    Forty fields, not forty-one.

    foreach my $i ( 0 .. 39 ) {


:         if ( defined $fields[$i] ) {

    Every field in @fields will be defined. "split" cannot return
undefined fields as it is used here. It *can* return empty fields
(''). The only undefined fields are the fields added for columns
with less than 40 columns.


:             $fields[$i] =~ s/\s*//;
:         } else {
:             $fields[$i] = "";
:         }
:     }

    We could use this to eliminate the space between some negative
numbers and the value.
    
    s/\s+//g foreach @fields;


:       if($START_MIN{$ctmp2[0]} < $Ctmp2[$i])
:           {
:            $END_MIN{$Ctmp2[0]}=$Ctmp2[$i];
:            print INV_RPT_MIN "$item~$END_MIN{$Ctmp2[0]}\n";       }
:    }

    You did say this code didn't work. Finding a minimum value
in an array would require iterating over each element, not just
these.

    We don't need any of that to get a minimum value with the
imported min() function.

                my $item = shift @fields;
                
                s/\s+//g foreach @fields;

        my $minimum = min( @fields );
                
                print INV_RPT_MIN "$item~$minimum\n";
                
: }
: close(INV_RPT);
: close(INV_RPT_MIN);
: ===============

    As tested:

    
use strict;
use warnings;

use List::Util 'min';

while ( <DATA> ) {

    my @fields  = split /~\s*/;
    my $item    = shift @fields;

    s/\s+//g foreach @fields;

    my $minimum = min( @fields );

    print "$item~$minimum\n";
}

__END__
AI6CQ7~Finishing Onhand~    48.0~    42.0~   134.0~   124.0~   
120.0~   120.0~   120.0~   110.0~   108.0~   102.0~    96.0~    
94.0~    94.0~    94.0~    90.0~    88.0~    88.0~    60.0~    
60.0~    60.0~    60.0~    60.0~   - 48.0~   -34.0~    24.0~    
18.0~    18.0~    18.0~    14.0~    98.0~    88.0~    88.0~    
88.0~    88.0~   -88.0~    82.0~    78.0~    68.0~    62.0~    
58.0~    58.0~    58.0~    56.0~    50.0~    44.0~    42.0~    
40.0~   140.0~   140.0~    96.0~    96.0~    96.0~    96.0~    
96.0~    -96.0~    -96.0~    56.0~    56.0~    56.0~    56.0~    
56.0~    56.0~    56.0~    56.0~    56.0~    56.0~    56.0~


HTH,


-- 
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
<http://learn.perl.org/> <http://learn.perl.org/first-response>


Reply via email to