2

Why is my perl code not printing out anything? I have been working on this for a while now and i am using a text file which has a ton of different data which each on of my arrays are sepearated by a comma meaning it is a column.

this is my code:

#!/usr/bin/perl

open (FILE, 'census2008.txt');

my @SumLevArray;
my @StNameArray;
my @CtyNameArray;
my @PopEstimateArary;
my @BirthsArray;
my @DeathsArray;

$i = 0;
$temp = 0;
$lowestBirthRates = 100000000;
$highestBirthRates = 0;
$size = 0;


while (<FILE>)
{
chomp;
($sumlev, $stname,$ctyname,$popestimate2008,$births2008,$deaths2008) = split(",");
push (@SumLevArray, $sumlev);
push (@StNameArray, $stname);
push (@CtyNameArray, $ctyname);
push (@PopEstimateArary, $popestimate2008);
push (@BirthsArray, $births2008);
push (@DeathsArray, $deaths2008);
}
$size = @BirthsArray;

while ($i < $size)
{
if($SumLevArray[$i] == " 040"){
$temp = $BirthsArray[$i]/$PopEstimateArary[$i]/541;
if(($lowestBirthRates > $temp) &&($temp > 0)){
$lowestBirthRates = $temp;
}
if($highestBirthRates < $temp){
$highestBirthRates = $temp;
}

}
$i = $i + 1;
}

print "\n";

print "Lowest birth rate in LOW-STATE: ";
print $lowestBirthRates;
print " per 541\n";

print "Highest birth rate in HIGH-STATE: ";
print $highestBirthRates;
print " per 541\n";

print "In Washington:\n";

print " Lowest birth rate in LOW-COUNTY County, WA: x.xxx per 541\n";

print " Highest birth rate in HIGH-COUNTY County, WA: x.xxx per 541\n";


close (FILE);
exit
user977154
  • 1,045
  • 4
  • 19
  • 39
  • 4
    **Always** start a Perl program with `use strict; use warnings;` and when you open a file, test to see if you succeeded as perl the [examples in the perldoc](http://perldoc.perl.org/functions/open.html). – Quentin Dec 10 '11 at 20:21
  • And don't roll your own CSV parser, use [Text::CSV](https://metacpan.org/module/Text::CSV), it is faster and handles lots of edge cases. – Quentin Dec 10 '11 at 20:22
  • @Quentin : In principle I agree with the `Text::CSV` recommendation but it looks like the OP has a long way to go before they are even comfortable with using modules. It's all part of the learning curve – Zaid Dec 10 '11 at 20:28
  • I fixed my code and i get my answers to be Lowest birth rate in LOW-STATE: 1.96871788504776e-05 per 541 Highest birth rate in HIGH-STATE: 3.84968878227209e-05 per 541. how do i get rid of the "e"? – user977154 Dec 10 '11 at 20:40
  • 2
    @user977154 : That should be asked as another question. Do accept an answer if it helped you. – Zaid Dec 10 '11 at 21:06
  • @user977154 look into [`printf`](http://p3rl.org/printf) and [`sprintf`](http://p3rl.org/sprintf) for printing and storing with formatting. – Joel Berger Dec 11 '11 at 14:29

8 Answers8

4

The best tool to help you out here is use strict; use warnings;. Make it a point to put it at the top of every script you write as it will save you a ton of time debugging trivial issues.

Here, there are a couple of is that are missing their $ sigil.

Also, consider studying the Perl data structure cookbook: perldoc perldsc. An array of hashes (technically hashrefs) would be a more scalable choice of data structure to store your data.

Community
  • 1
  • 1
Zaid
  • 36,680
  • 16
  • 86
  • 155
1

Try:

open (FILE, 'census2008.txt') or die $!;

The open may be failing without you knowing it.

Christopher Neylan
  • 8,018
  • 3
  • 38
  • 51
1

When you print something, ending it with a newline will cause it to be printed immediately, otherwise the text goes to the print buffer but the buffer is not flushed.

Dan
  • 10,531
  • 2
  • 36
  • 55
1

You should unbuffer stdout.

Add the following after #!/usr/bin/perl

$| = 1;

Having said that, here are a couple other things I would suggest:

1.) At minimum use strict; (use warnings is also advised)

Strict will force you to use "my" to declare your variables where you don't already do so. I can't tell you the number of times I've seen a programmer search and search for a bug that is easily detectable when turning on strict checking. (Typos on var names is a common one)

2.) Use the following for open

open($FILE, "<", 'census2008.txt') || die("Cannot open file!");

This will not only inform you if a file can't be opened for writing (due to the use of die), but using $FILE instead of a raw file handle will cause the file to be closed automatically when it goes out of scope.

RC.
  • 27,409
  • 9
  • 73
  • 93
  • That should be `open $FILE, '<', ...` (note the less than, not greater than sign – AFresh1 Dec 10 '11 at 22:27
  • Thanks. For some reason when I was typing it up I forgot the file was the data he was processing and not a file he was writing the result too. – RC. Dec 10 '11 at 22:31
  • It is not possible to "unbuffer stdout" as perl uses stdio.h, which is a buffered library. Setting $|=1 enables autoflush, it does not unbuffer stdout. – tadmc Dec 11 '11 at 00:32
1

Beyond using Text::CSV as others have suggested, just for fun I have rewritten the code as I might have written it. It includes many of the suggestions made here and a few of my personal style choices. If you have any questions about it please ask. Also if you can post some sample data, I can check to see that it works.

#!/usr/bin/env perl

use strict;
use warnings;

my $lowestBirthRates = 100000000;
my $highestBirthRates = 0;

my $filename = 'census2008.txt';
open (my $fh, '<', $filename) or die "Cannot open $filename: $!";

my %data;

while (<$fh>) {
  chomp;
  my ($sumlev, $stname,$ctyname,$popestimate2008,$births2008,$deaths2008) = split(",");

  push (@{$data{SumLev}}, $sumlev);
  push (@{$data{StName}}, $stname);
  push (@{$data{CtyName}}, $ctyname);
  push (@{$data{PopEstimate}}, $popestimate2008);
  push (@{$data{Births}}, $births2008);
  push (@{$data{Deaths}}, $deaths2008);
}

my $i = 0;
my $size = @{$data{Births}};

while ($i < $size) {

  if ( $data{SumLev}[$i] eq " 040" ){
  #if ( $data{SumLev}[$i] == 40 ){

    my $temp = $data{Births}[$i] / $data{PopEstimate}[$i] / 541;

    if( $lowestBirthRates > $temp && $temp > 0 ){
      $lowestBirthRates = $temp;
    }

    if ( $highestBirthRates < $temp ){
      $highestBirthRates = $temp;
    }

  }

  $i++;
}

print <<REPORT;
Lowest birth rate in LOW-STATE: $lowestBirthRates per 541
Highest birth rate in HIGH-STATE: $highestBirthRates per 541
In Washington:
Lowest birth rate in LOW-COUNTY County, WA: x.xxx per 541
Highest birth rate in HIGH-COUNTY County, WA: x.xxx per 541
REPORT

if you have the luxury of having Perl version 5.14 or greater installed, you can use an even clearer syntax, where push can take references directly, and where each can give the index in question as well as the value.

#!/usr/bin/env perl

use strict;
use warnings;

use 5.14.0;

my $lowestBirthRates = 100000000;
my $highestBirthRates = 0;

my $filename = 'census2008.txt';
open (my $fh, '<', $filename) or die "Cannot open $filename: $!";

my %data = (
  SumLev => [],
  StName => [],
  CtyName => [],
  PopEstimate => [],
  Births => [],
  Deaths => [],
);

while (<$fh>) {
  chomp;
  my ($sumlev, $stname,$ctyname,$popestimate2008,$births2008,$deaths2008) = split(",");

  push ($data{SumLev}, $sumlev);
  push ($data{StName}, $stname);
  push ($data{CtyName}, $ctyname);
  push ($data{PopEstimate}, $popestimate2008);
  push ($data{Births}, $births2008);
  push ($data{Deaths}, $deaths2008);
}

while (my ($i, $births) = each $data{Births}) {

  if ( $data{SumLev}[$i] eq " 040" ){
  #if ( $data{SumLev}[$i] == 40 ){

    my $temp = $births / $data{PopEstimate}[$i] / 541;

    if( $lowestBirthRates > $temp && $temp > 0 ){
      $lowestBirthRates = $temp;
    }

    if ( $highestBirthRates < $temp ){
      $highestBirthRates = $temp;
    }

  }
}

print <<REPORT;
Lowest birth rate in LOW-STATE: $lowestBirthRates per 541
Highest birth rate in HIGH-STATE: $highestBirthRates per 541
In Washington:
Lowest birth rate in LOW-COUNTY County, WA: x.xxx per 541
Highest birth rate in HIGH-COUNTY County, WA: x.xxx per 541
REPORT

Finally here is an implementation using Tie::Array::CSV which I wrote to be able to use a CSV file just like a 2D array in Perl (i.e. Array of ArrayRefs). It uses Text::CSV to do the parsing and Tie::File to do line access. This means that you don't need to store all the data in memory like in the previous examples.

#!/usr/bin/env perl

use strict;
use warnings;

use Tie::Array::CSV;

my $lowestBirthRates = 100000000;
my $highestBirthRates = 0;

my $filename = 'census2008.txt';
tie my @data, 'Tie::Array::CSV', $filename
  or die "Cannot tie $filename: $!";


foreach my $row (@data) {
  my ($sumlev, $stname, $ctyname, $popest, $births, $deaths) = @$row;

  if ( $sumlev eq " 040" ){
  #if ( $sumlev == 40 ){

    my $temp = $births / $popest / 541;

    if( $lowestBirthRates > $temp && $temp > 0 ){
      $lowestBirthRates = $temp;
    }

    if ( $highestBirthRates < $temp ){
      $highestBirthRates = $temp;
    }

  }
}

print <<REPORT;
Lowest birth rate in LOW-STATE: $lowestBirthRates per 541
Highest birth rate in HIGH-STATE: $highestBirthRates per 541
In Washington:
Lowest birth rate in LOW-COUNTY County, WA: x.xxx per 541
Highest birth rate in HIGH-COUNTY County, WA: x.xxx per 541
REPORT
Joel Berger
  • 20,180
  • 5
  • 49
  • 104
0

Try modifying your first lines of code to:

#!/usr/bin/perl

use strict;
use warnings;

$| = 1; #

open (FILE, 'census2008.txt');

After solving the errors/warnings that are appearing, all should be ok.

Tudor Constantin
  • 26,330
  • 7
  • 49
  • 72
0

To access the array you use i instead of $i as index.
Beyond this, I don't understand what you want to do inside the while loop.

Simone-Cu
  • 1,109
  • 8
  • 21
0

There is a problem in the line:

if($SumLevArray[$i] == " 040"){

This line is evaluated to true for many values of $SumLevArray[$i] ie "40", "040", " 00040 "

if $SumLevArray[$i] is an integer, this line should be:

if($SumLevArray[$i] == 40){

if $SumLevArray[$i] is a string, this line should be:

if($SumLevArray[$i] eq " 040"){
Toto
  • 89,455
  • 62
  • 89
  • 125