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

Hey everyone,

I am in a bit of a twist here since i am new to perl, Let me give you what the problem is first then following the problem I am pasting the script and output below.

Here is what I am trying to accomplish, I am parsing a directory which contains files, and getting some values and pushing those values in an array, Now this array contains duplicate values, which I get the count of each time a duplicate value has occured in the array, after that I remove the multiple values of an array so that my array doesn't have duplicate values.
Now for each value in the array I need to parse a file , find that element and grab another value say transport, which I am able to do ...BUT NOW THE TRICKY part for me is to display all that in the following output:

ELEMENT OF ARRAY |  NUMBER OF TIMES |  TRANSPORT

I can display the values like below

ELEMENT OF ARRAY | NUMBER OF TIMES

once that output is done then the other output which follows is below

ELEMENT OF ARRAY  |  TRANSPORT

can anyone help me out here .. please do note i am really new to perl

thanks

below is my script

#!/usr/bin/perl use Getopt::Long; &GetOptions('date=s' => \$date, 'dir=s' => \$directory, 'help' => \$help); if ( defined $help ) { usage(); } unless ( defined $date ) { usage(); } ####################################### # Declaring my variables below for # # the script # ####################################### my $PATH = "/Ack/$date/"; my $ID; my $TRANSPORT; my $ftpoutbound = "/homes/ftpoutbound.db"; my %count; my @id; my $temp; opendir (DIR, $PATH) || die print "can't open dir $PATH at line 62 : $ +!\n"; my @FileList = readdir(DIR); close (DIR); foreach $FileList(@FileList) { if ( ($FileList eq ".") || ($FileList eq "..") ) { next; } else { chomp $FileList; open (FILE, "$PATH$FileList") or die ("can't open $PATH$FileList + :$!\n"); @LINES=<FILE>; close FILE; foreach $LINES(@LINES) { @Fields = split (/[\|\*~]/, $LINES); if ( $Fields[5] =~ /^ZZ$/ ) { $ID = $Fields[6]; push (@id, $ID); } } } } $count{$_}++ for @id; print "$_ => $count{$_}\n" for keys %count; %temp = (); @id = grep ++$temp{$_} < 2, @id; open (File, "$ftpoutbound") or die ("can't open $ftpoutbound at line * +* : $!\n"); @FTP_Lines=<File>; close File; foreach $id(@id) { $id =~ s/\s+//; foreach $FTP_Lines(@FTP_Lines) { chomp $FTP_Lines; @FTP_fields = split (/\;/, $FTP_Lines); if ( $FTP_fields[0] eq $Clec_id ) { $TRANSPORT = $FTP_fields[7]; #print "C => $id and TRANSPORT => $TRANSPORT\n"; } } print ("$id uses $TRANSPORT as transport\n"); } # help/usage message and exits sub usage { print "Usage: \n"; print "This program requires one argument, w/ an optional help argum +ent.\n"; print "Options should be specified as follows: \n"; print "--date REQURIED Takes in the mmddyyyy format on +ly\n"; print "--help OPTIONAL Prints this message.\n"; print "example: ./TransactionsPerDay.pl --date 09152003 \n"; exit(1); }

below is the output
RHYTHMSIAVZSP => 117 ALGXSOULSOG5 => 1 SPNTVRZPRD => 69 2037721000SORD => 1 NEXTXOVENORDIAP => 5 VZEAPIPO => 27 VZELFLPO => 2 SGWEASTPROD => 41 TALKLSOG5 => 406 VZAPRODBAN => 21 gntftp5p => 98 NVEECIPO => 3 NVEDLCPO => 15 NVEIGCPO => 6 VZAPRODBAS => 24 VORDBAN2 => 234 VORDBAN2 uses SSL as transport COVADVZESORDP uses yes as transport ASHEESH uses yes as transport VORDBAS2 uses SSL as transport CMSTVZEORDP uses SSL as transport RHYTHMSIAVZSP uses SSL as transport TALKLSOG5 uses SSL as transport COVADVZENORDP uses yes as transport DSLNETBANORD uses yes as transport
Below is the desired output I want
RHYTHMSIAVZSP 12 SSL COVADVZ 245 yes ATT 33 NDM
I hope I have provided all the information

thanks

BazB edit, reformat/fix code tags. Add readmore.

Replies are listed 'Best First'.
Re: Help on displaying the output of two arrays
by Roger (Parson) on Oct 30, 2003 at 00:09 UTC
    Your solution is not very efficient because it iterates too much unnecessarily. What you need is to build a hash table to store the necessary data before printing them at the end. Here's my attempt at your code...
    #!/usr/bin/perl use strict; use Getopt::Long; use Data::Dumper; use IO::File; &GetOptions( 'd|date=s' => \(my $DATE), 'p|path=s' => \(my $PATH), 'h|help' => \(my $HELP) ); usage() if defined $HELP or ! (defined $DATE || defined $PATH); $PATH = "/Ack/$DATE" unless defined $PATH; my $ftpoutbound = "/homes/ftpoutbound.db"; my @FileList; opendir (DIR, $PATH) or die "Can't open dir $PATH $!"; while (my $f = readdir(DIR)) { next if -d $f; push @FileList, $f; } closedir DIR; # print Dumper(\@FileList); my %data; foreach my $file (@FileList) { my $f = new IO::File "$PATH/$file", "r" or die ("can't open $PATH/$file :$!"); while (<$f>) { my @rec = split /[\|\*~]/; if ($rec[5] eq "ZZ") { my $id = $rec[6]; $id =~ s/\s+//; $data{$id}{COUNT}++; } } } # print Dumper(\%data); # merge data into %data structure with values from FTP file my $f = new IO::File "$ftpoutbound", "r" or die "can't open $ftpoutbound :$!"; while (<$f>) { chomp; my @ftp_fields = split /;/; if (exists $data{$ftp_fields[0]}) { $data{$ftp_fields[0]}{TRANSPORT} = $ftp_fields[7]; } } undef $f; # display the results foreach (sort keys %data) { printf "%s|%s|%s\n", $_, $data{$_}{COUNT}, $data{$_}{TRANSPORT}; } sub usage { print <<EOL Usage: This program requires one argument, w/ an optional help argument. Options should be specified as follows: -d|date OPTIONAL Takes in the mmddyyyy format only. -p|path OPTIONAL Specifies a particular path. -h|help OPTIONAL Prints this message. example: ./TransactionsPerDay.pl --date 09152003 EOL ; exit(1); }
    Note that I have added the Data::Dumper module in the code to inspect the structure of the hash table. I haven't tested the code, but I am confident that it would work. :-D

Re: Help on displaying the output of two arrays
by QM (Parson) on Oct 29, 2003 at 21:38 UTC
    You probably want to use a nested hash...

    In the first set of loops, where you have:

    $ID = $Fields[6]; push (@id, $ID);
    change it to:
    $ID = $Fields[6]; $id{$ID}{count}++; # keep track of unique ID counts
    [Don't forget to declare my %id with your other variables. And use warnings; and use strict;]

    Then later you have:

    foreach $id(@id)
    rework this for the hash as:
    foreach my $id(keys %id)
    When you find the transport, add it to the hash like this:
    $id{$id}{transport} = $TRANSPORT;
    You can print this out right here if you like:
    printf "%-20s %5d %10s\n", $id, $id{$id}{count}, $id{$id}{transport};
    [though you will want %-5d if you really need the numbers left justified in the field.]

    Update: I don't know how you keep track of IDs in the transport section. There seems to be a typo at $Clec_id.

    Also, the transport section is not efficient. You can probably construct it similar to this:

    foreach $FTP_Lines(@FTP_Lines) { chomp $FTP_Lines; @FTP_fields = split (/\;/, $FTP_Lines); if ( defined($id{$FTP_fields[0]} ) { $TRANSPORT = $FTP_fields[7]; $id{$id}{transport} = $TRANSPORT; printf "%-20s %5d %10s\n", $id, $id{$id}{count}, $id{$id}{transport}; } }
    -QM
    --
    Quantum Mechanics: The dreams stuff is made of

      Hi QM,

      I did those changes as you told me .. but the output didn't come as wanted ..it was totally different, If you don't mind can u do the changes and paste me the script.. I might be changing something which i should not be.
      Thanks alot

      Edit BazB: removed code tags.

        ...can u do the changes and paste me the script...
        As I noted in my update, there are some things I can't track down in your original, such as what id has to do with transport.

        It would be better for you to paste the updates you've made, so we can better advise you.

        -QM
        --
        Quantum Mechanics: The dreams stuff is made of

Re: Help on displaying the output of two arrays
by delirium (Chaplain) on Oct 30, 2003 at 00:36 UTC
    Another rewrite attempt. Simplify everything you can. That makes your code easier to figure out in the future when you come back to it. Also, hashes can be nested, and I couldn't see a good reason to keep the @id array.

    This may not work without some tweaking, but hopefully it will at least get you started.

    #!/usr/bin/perl use Getopt::Long; &GetOptions('date=s' => \$date, 'dir=s' => \$directory, 'help' => \$help); &usage if ( defined $help || !defined $date ); my $PATH = "/Ack/$date/"; my $ftpoutbound = "/homes/ftpoutbound.db"; my %hash = (); opendir (DIR, $PATH) || die print "can't open dir $PATH at line 62 : $ +!\n"; my @FileList = readdir(DIR); close (DIR); foreach $FileList(@FileList) { next if $FileList =~ /^\.\.?$/; chomp $FileList; open (FILE, "$PATH$FileList") or die ("can't open $PATH$FileList :$ +!\n"); while(<FILE>) { @Fields = split /[\|\*~]/; # EDI data? $hash{$Fields[6]}{count}++ if ( $Fields[5] eq 'ZZ' ); # EDI? } } open (File, "$ftpoutbound") or die ("can't open $ftpoutbound at line * +* : $!\n"); while (<File>) { chomp; my @fields = split /\;/; $fields[0] =~ s/\s+//; $hash{$fields[0]}{transport} = $FTP_fields[7] if defined $hash{$FTP_ +fields[0]}; } print "$_ - $hash{$_}{count} - $hash{$_}{transport}\n" for keys %hash; sub usage { print "blah blah blah\n"; exit 1; }
Re: Help on displaying the output of two arrays
by tcf22 (Priest) on Oct 29, 2003 at 21:11 UTC
    Take a look at formats. These should help you get the desired output.

    - Tom