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

Hello!
I have a text file which looks like this(a portion of it):
test.txt 2004,21,22 2004,23,24 2004,25,26 . . . .
I need to split the text on whitespace and store in an array @data, so that each row gets stored in one array
element i.e.
$data[0]=2004,21,22 $data[1]=2004,23,24
and so on for other rows.

Once I have a row in each array element- I need to split again on comma, and store each item in one element of
another array

So I need to split on whitespace to get
$data[0]=2004,21,22 $data[1]=2004,22,23
And then in another array say @arr1
$arr1[0]=2004 $arr1[1]=21 $arr1[2]=22
in another array @arr2
$arr2[0]=2004 $arr2[1]=23 $arr2[2]=24
and so on for @arr3, @arr4( as many arrays as there are rows).Or is there a better way to do this?

At any point in the code I need to be able to access any row, and any item(e.g.'2004' or '22') in that row

Any suggestions? Here is the code I tried, but it's not working.
open DAT, 'test.txt' or die $!; my @data; my @row; while(<DAT>){ chomp; push @data,split; #print"\n$data[0]"; #print"\n$data[1]"; #print"\n$data[2]"; } $ldata=@data; #print"\n$ldata"; for($i=0;$i<$ldata;$i++){ #print"\nThe row:"; #print "\n$data[i]"; push @row,split(/,/,$data[i]); print"\nThe contents of the row:"; foreach $item(@row) { print "\nThe element:"; print "\n$item"; } } close DAT;
The contents of @data are printing correctly in the while loop, but not in the for loop outside, so the contents of
@row are not printing correctly either.
Any help would be appreciated.
Thanks :)

20040615 Edit by Corion: Changed title from 'Arrays'

Replies are listed 'Best First'.
Re: Splitting text into arrays
by Happy-the-monk (Canon) on Jun 12, 2004 at 08:31 UTC

    How about:

    use Data::Dumper; open(DAT, "< file") or die $!; while(<DAT>) { chomp; push @data, [ split( /,/ ) ]; # or split( /,/, $_ ) } print Dumper \@data;

    The while loop reads line by line, so it takes care about the splitting on newlines already.
    The split on comma is inside square brackets - these create an anonymous array around the results of split.
    That array is pushed on  @data.

    Cheers, Sören

      Hi Happy,
      that helps, thanks for your time.
      perl_seeker
      Hi Happy,

      that helps, thanks for your time.

      perl_seeker
Re: Splitting text into arrays
by Mr. Muskrat (Canon) on Jun 12, 2004 at 16:47 UTC

    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
      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 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