PDA

View Full Version : splitting many array elements for putting in a hash.


bazz
02-19-2006, 06:39 PM
OK, so I have an array item which could have as many as 600 elements separated by a comma and which, I read in from (config) flat file.

surely there is a more efficient method than this:


my @array = 1,2,3,4,5,6.....500;
my ($firstElement, $secondElement, $FiveHundredthElement) = split /\,/ , @array, 500;


The array will not always have 500 elements, as mostly it will have about 50 +/- 25.
Maybe I should reconfure the inputter to the Config file, so that each room number is in a separate array?


Perhaps there's a default variable which I could use in a foreach loop?

Bazz

FishMonger
02-19-2006, 07:02 PM
surely there is a more efficient method than this:There sure is, and I'm sure you know what my answer will be. :) :) A mysql database. :) :)

Can you give me more info on the array you're splitting and the hash you want to build from that split?

Assuming each array element is a comma seperated list, you could fill a temp array of the split fields and then a map command on that 2nd array. I'll wait until you post more details before I work up any code.

bazz
02-19-2006, 07:22 PM
Each array is separated by a comma but I thought it would be very verbose to split the array on perhaps 500 $variables.

The array would be comprised like this:

01,02,04,05,06 and in other cases
101,102, thru to 199,201,202,203 thru to 299 and so on.

The file reading in the data is as follows.

### open config file to readIn data for process #####
my $dat_file ="/domains/574/2317/html/cgi-bin/$clientsReservationsDir/Config"; # location of config file

open DAT, "< $dat_file" || die "couldnt open file\n";
while ( my $Line = <DAT> ) {
last if ( index($Line, ':') == -1 );
chomp $Line;
my ( $Keyword, $Value ) = split /:/, $Line, 2; #splits the line at the first : ignoring any others
if ($Keyword eq "AccommName") {
$AccommName = $Value;
} elsif ($Keyword eq "NumberOfDoubleRooms") {
$NumberOfDoubleRooms = $Value;
} elsif ($Keyword eq "DoubleRoomNumbers"){
@DoubleRoomNumbers = $Value;
} elsif ($Keyword eq "NumberOfSingleRooms") {
$NumberOfSingleRooms = $Value;
} elsif ($Keyword eq "SingleRoomNumbers") {
@SingleRoomNumbers = $Value;
} elsif ($Keyword eq "NumberOfFamilyRooms") {
$NumberOfFamilyRooms = $Value;
} elsif ($Keyword eq "FamilyRoomNumbers") {
@FamilyRoomNumbers = $Value;
} elsif ($Keyword eq "NumberOfTwinRooms") {
$NumberOfTwinRooms = $Value;
} elsif ($Keyword eq "TwinRoomNumbers") {
@TwinRoomNumbers = $Value;
} elsif ($Keyword eq "DoubleRoomRackRate") {
$DoubleRoomRackRate = $Value;
} elsif ($Keyword eq "SingleRoomRackRate") {
$SingleRoomRackRate = $Value;
} elsif ($Keyword eq "TwinRoomRackRate") {
$TwinRoomRackRate = $Value;
} elsif ($Keyword eq "FamilyRoomRackRate") {
$FamilyRoomRackRate = $Value;
} else {
warn "unknown field";
}

}


close DAT;






I am trying to run a loop which will result in the creation of a filename like this

Double_01_2008-01-04
RoomType_RoomNumber_Date(yyyy-mm-dd).


This part of the code is meant to build the RoomType and RoomNumber.

Ultimately the whole script, will create a Dir and in it, an empty file named for each roomType_RoomNumber_date in that year.

Bazz

Separately I have the code for creating the date though it only does the year and dates so far.

FishMonger
02-19-2006, 07:57 PM
I've got 1 or 2 ideas, but I'll need to do some testing before I make a recommendation.

I say this with all due respect, you can not expect to create an application as large and complex as you're doing without the use of a relational database and or proper config files.

You need to take a serious look at these config modules.

http://search.cpan.org/~tlinden/Config-General-2.31/General.pm
http://search.cpan.org/~nikratio/Config-Generic-0.01/lib/Config/Generic.pm
http://search.cpan.org/~kirsle/Config-INI-Simple-0.01/lib/Config/INI/Simple.pm
http://search.cpan.org/~mgraham/Config-Context-0.10/lib/Config/Context/XMLSimple.pm

FishMonger
02-19-2006, 08:07 PM
My first recommendation, which is just for cleanup purposes, is to drop all of those elsif blocks.
my %accomidations;
while ( chomp (my $Line = <DAT>) ) {
last if ( index($Line, ':') == -1 );
my ( $Keyword, $Value ) = split /:/, $Line, 2; #splits the line at the first : ignoring any others
$accomidations{$keyword} = $value;
}

FishMonger
02-19-2006, 08:42 PM
Here's an abbreviated version that does what you need.

#!/usr/bin/perl -w

$date = '2008-01-04';

%accomidations = ('SingleRoomNumbers' => '1,2,3,4,5',
'DoubleRoomNumbers' => '6,7,8,9,10',
);

foreach ( qw(SingleRoomNumbers DoubleRoomNumbers) ){
$type = $1 if $_ =~ /^(.*?)RoomNumbers/;
@rooms = split ',', $accomidations{$_};
foreach $room (@rooms) {
print join ('_', ($type, $room, $date)), $/;
}
}

Outputs:
Single_1_2008-01-04
Single_2_2008-01-04
Single_3_2008-01-04
Single_4_2008-01-04
Single_5_2008-01-04
Double_6_2008-01-04
Double_7_2008-01-04
Double_8_2008-01-04
Double_9_2008-01-04
Double_10_2008-01-04

bazz
02-21-2006, 04:49 PM
@ FishMonger, that works great now. Having had to build a Hash to create the date, I have learned some more. :) Quite chuffed, really.

@everyone,

All done now, but for making the script work out the number of days in each month. Presently it 'thinks' there are 31 in each month.

I would think that making a separate hash for each month type, (30 31 28/29 days), would be excessive so I wonder whether I should use code to exit the loop after a specified number of times (set conditionally) or, should I make a hash like this,


my %months (

January => 01,
January => 02,
January => 03 etc
January => 31,

February => 01
February => 02
February => 03
February => 04
February => 28

FebruaryLeap => 29


or should I use an array for the number of dates in a conditional



if ($month eq "April" || $month eq "September" || $month eq "June" || $month eq "November"){
my @potentialDatesOfMonth =('01','02','03','04','05','06','07','08','09','10','11','12','13','14','15','16','17','18','19','20 ','21','22','23','24','25','26','27','28','29','30');
print "pDoM = @potentialDatesOfMonth<br />";
}
if ( $yearDivided =~ m/\./ && $month eq 'February' ) {
my @potentialDatesOfMonth =('01','02','03','04','05','06','07','08','09','10','11','12','13','14','15','16','17','18','19','20 ','21','22','23','24','25','26','27','28');
print "pDoM = @potentialDatesOfMonth<br />";
} elsif ( $month eq 'February' ){
print "$nextYear is a leap Year<br />";
my @potentialDatesOfMonth =('01','02','03','04','05','06','07','08','09','10','11','12','13','14','15','16','17','18','19','20 ','21','22','23','24','25','26','27','28','29');
print "pDoM = @potentialDatesOfMonth<br />";
}
if ( $month eq "January" || $month eq "March" || $month eq 'May' || $month eq 'July' || $month eq ' August' || $month eq 'October' || $month eq 'December' ) {
my @potentialDatesOfMonth =('01','02','03','04','05','06','07','08','09','10','11','12','13','14','15','16','17','18','19','20 ','21','22','23','24','25','26','27','28','29','30','31');
print "pDoM = @potentialDatesOfMonth<br />";

}



This is the code from the appropriate point in the script:



foreach my $Month (sort values %months) {
print "month1 =$Month<br />\n"; #successful


foreach $Date (sort values %dates) {

$YMD = join ("-", ($nextYear, $Month, $Date));
#print "$YMD\n"; # successful

foreach ( qw( SingleRoomNumbers DoubleRoomNumbers TwinRoomNumbers FamilyRoomNumbers ) ){
$type = $1 if $_ =~ /^(.*?)RoomNumbers/;
@rooms = split ',', $accommodations{$_};
foreach $room (@rooms) {
my $filenames = join ('_', ($type, $room, $YMD)), $/;
print "fileNames = $filenames<br />\n";
}
}
}
}



Bazz

FishMonger
02-21-2006, 05:24 PM
Is there some reason you don't want to use one of the date modules?
Date::Calc http://search.cpan.org/~stbey/Date-Calc-5.4/Calc.pod
Date::Manip http://search.cpan.org/~sbeck/DateManip-5.44/Manip.pod

If you want to do it manually, I'd probably use a hash that gives the number of days for each month.

my %months = (
January => 31,
February => 28,
March => 31,
etc,
);

Then you can loop through each month of the hash using its value as the exit point for the next loop.