Question

I've just been completing an assignment - I asked a question about this last week and was advised not to use a Smart Match Operator, but I have a greater grasp of it over Hashes.

Basically this subroutine is one of 4 subroutines. It Opens a file containing 125,000 mammals, loads it into a list, loops over the list and splits it into scalars. Loads parts of the split list into a calculator which returns a value ($Calcdist).

What I want this to do it basically count the number of species in the area which is does do. somewhat. The data I'm using at the moment is:

$File =("Mammal.txt");
$Distance = 5.0;
$Lat = 51.75;
$Long = -1.25;

With this information it tells me there are 95 animals in that area (using another subroutine) This subroutine should tell me that there are 30 unique species but instead it prints the number 9.

Where abouts am I going wrong? Is my 'if' and 'else' incorrect? I know there are much better ways of coding perl but this is just the way I have been taught.

sub BiodiversityCount ($$$$)
     {
          my ($Filename, $Distance, $Lat1, $Lon1) = @_;
          my ($Line, $Index, $CalcDist, $Counter, $Counter2, $Index2);
          my (@List, @Part, @Species);
          open (INF, "<", $Filename) or die ("Cannot open Mammal.txt\n");
          @List = <INF>;
          close (INF);
          for ($Index=0;$Index<@List;$Index++)
               {
                   @Part = split ("\t", $List[$Index]);
                   $CalcDist = CalculateDistance ($Lat1, $Lon1, $Part[1], $Part[2]);
                   if ($CalcDist<$Distance)
                       {                    
                           if ($Part[0] ~~ @Species)
                               {
                               $Counter++
                               }
                           else
                               {
                               @Species = $Part[0]; 
                               }                                    
                       }
              }
          #printf @Species;
          print("The number of unique species found upto $Distance km from $Lat1, $Lon1 is: $Counter\n");
          #Number of Unique species found in an area
          #Smart match operator
          #Hashes - declared using my %___
      }
BiodiversityCount ($File, $Distance, $Lat, $Long);

Test data:

Muntiacus reevesi
Muntiacus reevesi
Apodemus flavicollis
Mustela erminea
Lepus europaeus
Apodemus sylvaticus
Sciurus carolinensis
Talpa europaea
Arvicola amphibius
Rhinolophus ferrumequinum
Arvicola amphibius
Muntiacus reevesi
Apodemus sylvaticus
Sciurus carolinensis
Sciurus carolinensis
Sorex araneus
Erinaceus europaeus
Sciurus vulgaris
Vulpes vulpes
Clethrionomys glareolus
Sorex araneus
Meles meles
Arvicola amphibius
Microtus agrestis
Vulpes vulpes
Nyctalus noctula
Erinaceus europaeus
Neomys fodiens
Meles meles
Erinaceus europaeus
Capreolus capreolus
Pipistrellus pipistrellus sensu lato
Micromys minutus
Rattus norvegicus
Sorex minutus
Plecotus
Erinaceus europaeus
Muntiacus reevesi
Vulpes vulpes
Mustela erminea
Oryctolagus cuniculus
Dama dama
Erinaceus europaeus
Talpa europaea
Muntiacus reevesi
Muntiacus reevesi
Sciurus carolinensis
Vulpes vulpes
Sorex minutus
Talpa europaea
Talpa europaea
Muntiacus reevesi
Muntiacus reevesi
Muntiacus reevesi
Mustela vison
lethrionomys glareolus
Microtus agrestis
Sciurus vulgaris
Mustela nivalis
Apodemus sylvaticus
Meles meles
Meles meles
Vulpes vulpes
Capreolus capreolus
Mustela nivalis
Mustela putorius
Microtus agrestis
Sorex araneus
Sorex minutus
Muscardinus avellanarius
Muntiacus reevesi
Sciurus carolinensis
Dama dama
Muntiacus reevesi
Talpa europaea
Muntiacus reevesi
Microtus agrestis
Dama dama
Microtus agrestis
Talpa europaea
Arvicola amphibius
Muntiacus reevesi
Muntiacus reevesi
Muntiacus reevesi
Sorex minutus
Vulpes vulpes
Dama dama
Talpa europaea
Apodemus sylvaticus
Sorex araneus
Microtus agrestis
Lepus europaeus
Sorex minutus
Neomys fodiens
Vulpes vulpes
Was it helpful?

Solution

You might want a hash to count unique species. I made an adjustment to your code which uses a hash, %species_count. There are other changes you might make, but for now, I think this hash will get you what you want. (I also fudged $CalcDist = 1;#CalculateDistance ($Lat1, $Lon1, $Part[1], $Part[2]); to run the script, just change it back to what it was originally)

#!/usr/bin/perl
use strict;
use warnings;

my $File =("Mammal.txt");
my $Distance = 5.0;
my $Lat = 51.75;
my $Long = -1.25;

sub BiodiversityCount ($$$$)
     {
          my ($Filename, $Distance, $Lat1, $Lon1) = @_;
          my ($Line, $Index, $CalcDist, $Counter, $Counter2, $Index2);
          my (@List, @Part, %species_count);
          #open (INF, "<", $Filename) or die ("Cannot open Mammal.txt\n");
          chomp(@List = <DATA>);
          #close (INF);
          for ($Index=0;$Index<@List;$Index++)
               {
                   @Part = split ("\t", $List[$Index]);
                   $CalcDist = 1;#CalculateDistance ($Lat1, $Lon1, $Part[1], $Part[2]);
                   if ($CalcDist<$Distance)
                       {
                           $species_count{$Part[0]}++;
                       }
              }
          #printf @Species;
          #print("The number of unique species found upto $Distance km from $Lat1, $Lon1 is: $Counter\n");
          print("The number of unique species found upto $Distance km from $Lat1, $Lon1 is: ",  scalar keys %species_count, "\n");
          #Number of Unique species found in an area
          #Smart match operator
          #Hashes - declared using my %___
      }
BiodiversityCount ($File, $Distance, $Lat, $Long);

__DATA__
Muntiacus reevesi
Muntiacus reevesi
Apodemus flavicollis
Mustela erminea
Lepus europaeus
Apodemus sylvaticus
Sciurus carolinensis
Talpa europaea
Arvicola amphibius
Rhinolophus ferrumequinum
Arvicola amphibius
Muntiacus reevesi
Apodemus sylvaticus
Sciurus carolinensis
Sciurus carolinensis
Sorex araneus
Erinaceus europaeus
Sciurus vulgaris
Vulpes vulpes
Clethrionomys glareolus
Sorex araneus
Meles meles
Arvicola amphibius
Microtus agrestis
Vulpes vulpes
Nyctalus noctula
Erinaceus europaeus
Neomys fodiens
Meles meles
Erinaceus europaeus
Capreolus capreolus
Pipistrellus pipistrellus sensu lato
Micromys minutus
Rattus norvegicus
Sorex minutus
Plecotus
Erinaceus europaeus
Muntiacus reevesi
Vulpes vulpes
Mustela erminea
Oryctolagus cuniculus
Dama dama
Erinaceus europaeus
Talpa europaea
Muntiacus reevesi
Muntiacus reevesi
Sciurus carolinensis
Vulpes vulpes
Sorex minutus
Talpa europaea
Talpa europaea
Muntiacus reevesi
Muntiacus reevesi
Muntiacus reevesi
Mustela vison
lethrionomys glareolus
Microtus agrestis
Sciurus vulgaris
Mustela nivalis
Apodemus sylvaticus
Meles meles
Meles meles
Vulpes vulpes
Capreolus capreolus
Mustela nivalis
Mustela putorius
Microtus agrestis
Sorex araneus
Sorex minutus
Muscardinus avellanarius
Muntiacus reevesi
Sciurus carolinensis
Dama dama
Muntiacus reevesi
Talpa europaea
Muntiacus reevesi
Microtus agrestis
Dama dama
Microtus agrestis
Talpa europaea
Arvicola amphibius
Muntiacus reevesi
Muntiacus reevesi
Muntiacus reevesi
Sorex minutus
Vulpes vulpes
Dama dama
Talpa europaea
Apodemus sylvaticus
Sorex araneus
Microtus agrestis
Lepus europaeus
Sorex minutus
Neomys fodiens
Vulpes vulpes

OTHER TIPS

This line:

@Species = $Part[0]; 

Should be:

push @Species, $Part[0];

Also, you probably want to be chomping the lines you read from the file to remove the trailing line break characters.

You also have at least one logic error: I think you ought to be ++ing the counter only when not $Part[0] ~~ @Species.

You appear to be trying to use the ~~ operator (incorrectly) to perform a set-membership test.

Smartmatch has been re-declared as experimental, so you may wish to avoid it. You can avoid it and at the same time make your code clearer in intent, and actually work, by rewriting it. For example you could use the any function from List::Util:

if ($Part[0] ~~ @Species)

now becomes

if ( any { $Part[0] eq $_ } @Species )

In general you should avoid smartmatch for now, unless and until core perl decides on a better set of semantics for it, and declares it non-experimental again.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top