in reply to Splitting text into arrays

A slight improvement upon Happy-the-monk's reply. You see, you still need to know how to access the data. For that you can read perlreftut, perldsc and perllol. Then come back and look through my code.

#!/usr/bin/perl use strict; use warnings; my @data; open(DAT, '<', 'test.txt') or die $!; while(<DAT>) { chomp; push @data, [ split( /,/ ) ]; } close(DAT); for my $row ( 0 .. $#data ) { # iterate over each row by index for my $column ( 0 .. $#{$data[$row]} ) { # iterate over each column + by index print "row $row, column $column: $data[$row][$column]\n"; # displa +y using the notation from the Arrow Rule } } # now let's just print the data in the 1st row, 1st column (zero based + of course) print $data[1][1],"\n"; # valid, see above print $data[1]->[1],"\n"; # also valid, Rule 2 print ${$data[1]}[1],"\n"; # also valid, Rule 1

Replies are listed 'Best First'.
Re^2: Splitting text into arrays
by perl_seeker (Scribe) on Jun 21, 2004 at 05:52 UTC
    Hi,
    I'd be glad for a little more help on this.Suppose my file looks like this:
    test.txt 2004,21,21,1,16.00 2004,21,21,1,16.25 2004,22,22,1,18.00 2004,22,22,1,18.25
    The data in column 0 is the 'year', and that in column 2 is the 'day', so data in column 2 can have values from 1 to 31.In this table the only values we have are '21' and '22'.

    Actually, after populating the array of arrays with the data from the text file:

    I need to send in succession, the data from column 4 (say), for the col 2='21' rows,then the col 2='22' rows,.....and so on to a subroutine which will process the data in some way, and return a value to the main program.

    For example, for the col 2='21' rows the values ,16.00,16.25 will be send to a sub 'Process'.'Process' finds the biggest(maximum) number amongst the set, and returns that value to the main program(16.25).Next the values 18.00 and 18.25 will be sent to 'Process'(for the col 2='22' rows)and again a value will be returned to the main program.

    The day of the month may be from 1-31 , so we may need to send 31 sets of data to the sub 'Process'.

    Column 2 is sorted, first we have all the '21' rows, then the '22' rows, then the '23' rows and so on.

    All this sounds scary.I've tried doing things, with no luck. Any code or advice would be appreciated.
    Thanks ,
    perl_seeker:)
      You could use a HoA to store the data: col2 = key, col4 = values to be stored in the array. Then iterate thru the hash keys, send each value (an array) to a sub that returns the greatest value. The following does exactly that.

      #!/usr/bin/perl use Data::Dumper; use strict; my $k; my %hash; my @line; # iterate thru data and store values in hash while(<DATA>) { chomp($_); @line = split(",", $_); push @{ $hash{$line[2]} }, $line[4]; } # hash structure (in case you are curious) print "hash structure:\n"; print Dumper(\%hash); print "\n"; # iterate thru hash # send arrays to greatest sub print "greatest values for each key:\n"; foreach $k (keys %hash) { print "$k: " . &greatest( $hash{$k} ) . "\n"; } #return greatest value sub greatest() { my $arr = shift; my @a = sort { $b <=> $a } @{ $arr }; return $a[0]; } exit; __DATA__ 2004,21,21,1,16.00 2004,21,21,1,16.25 2004,22,22,1,18.00 2004,22,22,1,18.25
      output:
      hash structure: $VAR1 = { '22' => [ '18.00', '18.25' ], '21' => [ '16.00', '16.25' ] }; greatest values for each key: 22: 18.25 21: 16.25
      hope this helps,
      davidj
        Hi David,
        thanks a lot for your help, much appreciated.I did manage to get my code to work using an array of arrays itself(with the help of Happy's and Mr.Muskrat's code ), but maybe you have done it in a better way.I've included my code at the bottom of the post.Actually, I found out later that I need to keep track of the 'month'of the year as well, which is stored in column 3.So suppose the data looks like
        2004,21,21,1,16.00 2004,21,21,1,16.25 2004,22,22,1,18.00 2004,22,22,1,18.25 2004,21,21,2,16.00 2004,21,21,2,16.25 2004,22,22,2,18.00 2004,22,22,2,18.25
        So we need to keep track of the col 2='21' rows for col3='1'and col3='2'and again col 2='22'rows for col3='1' and col3='2', and so on. How would you change your code to do that? Also I need to have the 'day' and 'month' in double digit format('01' instead of 1 for example).

        My actual data has much longer rows.Here's what one looks like:
        2004,21,1,1,16.00,1600,18.62,20.28,16.86,3.225,1001,33.95,33.53,40.2,0 +,0,97.2,1.782,105.3,56.92,0,82.2
        And here' my code,assuming values of only '21' and '22' for 'day', and '1' and '2' for 'month' for all to see and comment on :) (thanks for your patience!)
        #!/usr/bin/perl use strict; use warnings; my @data; open(DAT, '<', 'testing.txt') or die $!; while (<DAT>) { chomp; push @data, [split(/,/)]; #store in array of arrays } close (DAT); my $count=0; for my $row (0..$#data){ #iterate over each row by index $count++; #print "\nThe number of rows:"; #print "\n $count"; for my $column(0..$#{$data [$row]}){ #iterate over each column by index #print "row $row, column $column:$data[$row][$column]\n"; #display using the notation from the arrow rule #the data in the row 1, column 1 #print $data [1][1],"\n"; #print $data [1]->[1],"\n"; #Rule 2 #print $ {$data [1]}[1],"\n"; #Rule 1 } } #print "\nThe number of rows:"; #print "\n $count"; open OUT, '>dailyrecords.xml' or die $!; print OUT "\n<AnnualWeatherRecord>"; my @max_drybulb; for (my $m=1;$m<=2;$m++){ for (my $d=21;$d<=22;$d++){ #print "\n$i"; #print"\n$n"; my @drybulb=map { $_->[11] } grep { (($_->[2] == $d) && ($_->[3] == $ +m)) } @data; my @wetbulb=map { $_->[12] } grep { (($_->[2] == $d) && ($_->[3] == $ +m)) } @data; my @rainfall=map { $_->[4] } grep { (($_->[2] == $d) && ($_->[3] == $ +m)) } @data; my $hyphen="-"; my @dates = map { "$_->[2]$hyphen$_->[3]$hyphen$_->[0]" } grep { (($ +_->[2] == $d) && ($_->[3] == $m)) } @data; my $date=&senddate(@dates); #print "The date for each of the sets:"; #print"\n@dates\n"; #print"\nThis set of data:"; #print"\n@drybulb\n"; #print"\nThis set of data:"; #print"\n@wetbulb\n"; #print"\nThis set of data:"; #print"\n@rainfall\n"; my $max_drybulb=&maxtemp(@drybulb); #print"\n$max_drybulb"; my $min_drybulb=&mintemp(@drybulb); #print"\n$min_drybulb"; my $max_wetbulb=&maxtemp(@wetbulb); #print"\n$max_wetbulb"; my $min_wetbulb=&mintemp(@wetbulb); #print"\n$min_wetbulb"; my $prec=&totrain(@rainfall); #print"\n$prec"; print OUT "\n<DailyWeatherRecord>"; print OUT"\n\t<date>$date</date>"; print OUT "\n\t<temperature>"; print OUT "\n\t\t<maxdrybulb units"; print OUT "=\"degrees-centigrade\" number=\"$max_drybulb\"/>"; print OUT "\n\t\t<mindrybulb units"; print OUT "=\"degrees-centigrade\" number=\"$min_drybulb\"/>"; print OUT "\n\t\t<maxwetbulb units"; print OUT "=\"degrees-centigrade\" number=\"$max_wetbulb\"/>"; print OUT "\n\t\t<minwetbulb units"; print OUT "=\"degrees-centigrade\" number=\"$min_wetbulb\"/>"; print OUT "\n\t</temperature>"; print OUT "\n\t<totalrainfall units"; print OUT "=\"mm/hr\" number=\"$prec\"/>"; print OUT "\n</DailyWeatherRecord>"; print OUT "\n\n\n\n"; } } print OUT "\n</AnnualWeatherRecord>"; close (OUT); sub maxtemp { my @max=@_; foreach my $item(@max){ #print "\nThe item:"; #print"\n$item"; } my $max=$_[0]; for (@max) { $max = $_ if $_ > $max } return $max; } 1; sub mintemp { my @min=@_; my $min=$_[0]; for (@min) { $min = $_ if $_ < $min } return $min; } 1; sub totrain { my @prec=@_; #print "\n@prec\n"; my $tot=0; foreach my $ritem(@prec){ $tot=$tot + $ritem; } return $tot; } 1; sub senddate{ my @dat=@_; foreach my $ditem(@dat){ return $ditem; } } 1;
        thanks,
        perl seeker:)
Re^2: Splitting text into arrays
by perl_seeker (Scribe) on Jun 13, 2004 at 07:56 UTC
    Hi Mr. Muskrat,
    thanks a lot for the code and your advice. I'll have to read, and try using the code.(I'll have to
    come back in case I have further questions).Thanks a lot.
    perl_seeker