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

Hello Monks, I am working on some code that will process through multiple elements in an array and calculate the total number of entires for each field.

The data is in a tab delimited file which I pull into an array and grab all the fields in a foreach loop. Next I want to proceed with a few of the calculations for the defined fields. In the case below, I want to count the total number of $caseNumber entries.

#!/usr/bin/perl use warnings; use strict; # open file my $file = shift @ARGV; open (FILE1, "<", $file) or die "Can't open '$file': $!"; # read file into an array my @data = <FILE1>; # close the file you don't need it any more close (FILE1); # Use a FOREACH loop to read through the data in the array foreach my $caseMetrics (@data) { (my $caseOwner,my $caseNumber,my $accountName,my $contactName, +my $openedDate,my $subject,my $status,my $priority,my $severity,my $a +geHours,my $caseOrigin,my $closedDate,my $highWaterMark,my $accountRe +gion,my $industryConcentratio,my $industry,my $apiType,my $applyFromA +pp,my $environmentAffecting,my $osBackend,my $osFrontend,my $version, + my $maintenanceLevel)=split('\t',$caseMetrics); #Calculate the number of total cases. sub total_cases{ my @closedCases = $caseNumber; my %caseCount; map {$caseCount{$caseNumber}++} @closedCases; return %caseCount; } }

I'm not sure that the sub routine is the way to go here. It doesn't work, nor does it throw an error (which is surprising given my lack of coding prowess). An important note here is that I tried the code as is and by omitting the "my @closedCases" array in the sub so, I think I am way off the rails here. I'm guessing that there is a better way to pull these kinds of counts from the array.

Any suggestions would be most appreciated! Thanks! Duke

Replies are listed 'Best First'.
Re: Counting multiple values in an array...
by jwkrahn (Abbot) on Jun 09, 2010 at 20:55 UTC

    1. You should indent your code properly so that it is easier to read.
    2. You don't need to read the whole file into an array in order to accomplish your task.
    3. You don't have to put my in front of every variable name in a list, you just need to put it in front of the left parenthesis for the entire list.
    4. You are only using one field ($caseNumber) from each record so there is no need to create variables for the other fields that you are not using.
    5. You are defining a subroutine but you never call the subroutine so the code inside it never runs.

    You may want something like this (UNTESTED):

    #!/usr/bin/perl use warnings; use strict; # open file my $file = shift @ARGV; open FILE1, '<', $file or die "Can't open '$file': $!"; my %caseCount; # Use a while loop to read through the data while ( <FILE1> ) { my $caseNumber = ( split /\t/ )[ 1 ]; $caseCount{ $caseNumber }++; } # close the file you don't need it any more close FILE1; #do something here with values in %caseCount

      You missed lecture point #0: use lexical filehandles!

        Sorry, I didn't attend that lecture.    :-)

Re: Counting multiple values in an array...
by toolic (Bishop) on Jun 09, 2010 at 20:52 UTC
    Since you didn't show any input data or expected output, it is difficult to understand what you are trying to accomplish. So, I'll just create some simple input with 3 lines, 3 tab-separated columns per line. This will count the number of times each string appears in the 2nd column:
    use strict; use warnings; use Data::Dumper; my @data = ( "o1 n1 a1\n", "o2 n2 a2\n", "o3 n1 a3\n", ); my %caseCount; for my $caseMetrics (@data) { my $caseNumber = (split /\t/, $caseMetrics)[1]; $caseCount{$caseNumber}++; } print Dumper(\%caseCount); __END__ Output... $VAR1 = { 'n2' => 1, 'n1' => 2 };

    Since you only seem to use 1 of the columns, just keep the one you want when you split. Splitting into multiple variables is hardly ever a good approach anyway; typically, you would split into an array.

Re: Counting multiple values in an array...
by dukea2006 (Novice) on Jun 10, 2010 at 13:24 UTC

    All,

    Thanks to everyone for their time and the specific examples. Also, thanks for the greater suggestions regarding formatting of my code, etc. I really appreciate it. You guys are always helpful when I paint myself into a corner, which is often.

    I'll dig back into this today.

    -Duke

Re: Counting multiple values in an array...
by deMize (Monk) on Jun 09, 2010 at 20:54 UTC
    I'm removing this comment because I did something bad and did not read your post thoroughly.. I'd remove it if I could.

    See my reply for further information.
      That's what you get for not reading.

      You stored it in a variable, which is fine sometimes, but something this straightforward, you don't need to, as said below.

      You'll find that there can be some performance impacts when storing whole files into variables, mainly RAM I/O.

      As said below, the main culprit why your function isn't doing anything is because you've only defined it, not called it. Adding to jwkrahn's code

      #!/usr/bin/perl use warnings; use strict; main(); sub main{ # open file my $file = shift @ARGV; open FILE1, '<', $file or die "Can't open '$file': $!"; my %caseCount; # Use a while loop to read through the data while ( <FILE1> ) { my $caseNumber = ( split /\t/ )[ 1 ]; $caseCount{ $caseNumber }++; } # close the file you don't need it any more close FILE1; #do something here with values in %caseCount # DoSomething is an example of how to call a function DoSomething(\%caseCount); } sub DoSomething{ my $hashref = shift; foreach my $key (sort keys %{$hashref}){ print "$key - ${$hashref}{$key}\n"; } }
      Notice that we've defined a main procedure called "main", which isn't necessary, but it is easier to comprehend for those C programmers. This way, there are no global variables.

      We've also shown an example of how to define and call a function, and how to pass a hash as a hash reference and then use it in the sub function/procedure.

      Update: because we are using a hashref the extra '$' was necessary in calling the value of for the key: $$hashref{$key}