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

help!! i'm working with a two-dimensional array in perl. i originally tested all my code using hard coded data...
@array = ( [ "A", "B", "C" ], [ "D", "E", "F" ], [ "G", "H", "I" ], );
then i iterate through my array using a some for loops...
for($col = 0; $col < $width; $col++) { for($row = 0; $row < $height; $row++) { $myString = $myString.$array[$row][$col]; } $myString =""; }
this worked fine until i tried reading from a data file copying the file into an array. when i try to run it i get:
"Use of unitialized value in concatenation... blah, blah"
i tried splitting the file into lines then elements but nothing seems to work. can anybody help me??? -confused

Replies are listed 'Best First'.
Re: 2 dimensional array
by kabeldag (Hermit) on Jun 23, 2008 at 05:43 UTC
    The "Use of unitialized value in concatenation... blah, blah" error may be because of the way that you are populating the array from the file. Or maybe it is because $myString isn't initialized before the concatenation and you are using warnings.

    It would be good if you post the code you are using to populate the array from the file, and how you are referencing the array elements.

    split may produce a leading undefined value, or a trailing undefined value depending on how you are trying to split the data in the file.

    Please post the code that doesn't work.

      wow. didn't expect anyone to read this so late. i haven't had a chance to analyze your response but here is part of the code:
      $datafile = $ARGV[0]; chomp $datafile; open (INPUT, $datafile) || die ("Unable to open $datafile"); @data = <INPUT>; close INPUT; @dim = split(/\,/, $data[0]); $width = $dim[0]; $height = $dim[1]; @table = @data[1..$height]; for($row = 0; $row < $height; $row++) { for($col = 0; $col < $width; $col++) { $myString = $myString.$table[$row][$col]; } $myString =""; }
      and the data file i'm reading is:
      15,10 ADESFJRASLXDFRT QBRAINOUEWHGYED RIRURLKUNGEASDV NAOBXCSTACHUIOL OJKDGKJGHJUINHR AHRHOAIDFSETRGH RXANOGSYEROGATS TOUDOGSDSAVFTRY UORTUOFRHRJUIKO BTIARTHYEUVFGQA Dogs, Cats Train
      thanks
        Ok. Well @table = @data[1..$height]; may not be doing what you expect.
        If you are unsure about your data structures or are just curious, then you can use Data::Dumper
        use Data::Dumper; $datafile = 'testdata.txt'; chomp $datafile; open (INPUT, $datafile) || die ("Unable to open $datafile"); @data = <INPUT>; close INPUT; @dim = split(/\,/, $data[0]); $width = $dim[0]; $height = $dim[1]; @table = @data[1..$height]; print Dumper(@table); die; for($row = 0; $row < $height; $row++) { for($col = 0; $col < $width; $col++) { $myString = $myString.$table[$row][$col]; } $myString =""; }
        @table is not a multi-dimensional array (because of the way you tried to create it). Therefore, there is no such
        $table[$row][$col]. Each element of @data is a single line of $datafile. @table = @data[1..$height]; is merely creating a new array which contains the same elements as @data.

        I don't know exactly know what you are trying to do, but to get access to each byte of each element/row in @table, you can use substr(). You don't need a 2-dimensional array for that:

        use strict; use warnings; my $datafile = $ARGV[0] || die "File to open was not provided!"; my @data; open (DATA_FILE, '<', $datafile) || die ("Unable to open $datafile"); @data = <DATA_FILE>; close(DATA_FILE); my @dim = split /\,/, $data[0]; my $width = $dim[0]; my $height = $dim[1]; my @table; push (@table, @data[1..$height]); my $myString =''; for(my $row = 0; $row < $height; $row++) { for(my $col = 0; $col < $width; $col++) { $myString .= substr($table[$row], $col, 1); } $myString =""; }
        That code leaves table as the one-dimensional array:
        @table = ( "ADESFJRASLXDFRT\n" "QBRAINOUEWHGYED\n" "RIRURLKUNGEASDV\n" "NAOBXCSTACHUIOL\n" "OJKDGKJGHJUINHR\n" "AHRHOAIDFSETRGH\n" "RXANOGSYEROGATS\n" "TOUDOGSDSAVFTRY\n" "UORTUOFRHRJUIKO\n" "BTIARTHYEUVFGQA\n" );
        But then you access it as if it were a two-dimensional array. (Your code actually will try to use symbolic references; you should enable strict so that when that happens by accident, you are alerted to it.)

        So, you need to add the code that would turn the above into a two dimensional array. What is each column going to be?

        You probably want to chomp(@data) after reading it to get rid of the newlines.

Re: 2 dimensional array
by starbolin (Hermit) on Jun 23, 2008 at 05:50 UTC

    Very hard to offer meaningful help without the code that is failing but I'll try anyway. You need to check the data that you read in before assigning it to the array. The read could return a null record. Especially the last read in the file can return an undef. This is generally not a problem when you use the  while(<FH>) construct because that is shorthand for  while(defined($_=<FH>)) but if you use other read methods you have to call defined() yourself.


    s//----->\t/;$~="JAPH";s//\r<$~~/;{s|~$~-|-~$~|||s |-$~~|$~~-|||s,<$~~,<~$~,,s,~$~>,$~~>,, $|=1,select$,,$,,$,,1e-1;print;redo}
      He's doing a list-context read, which will read all the records in the file and then stop. There is no concern that there be an undef included in the returned lines.
Re: 2 dimensional array
by jethro (Monsignor) on Jun 23, 2008 at 15:17 UTC
    @table= ... for ($col ... ) { for ($row ... ){ $array[$row][$col]= substr(@table[$row],$col,1); } }
    My advice would be to tell them at the interview that you had some trouble with this program even if you can finish it. The're bound to find out anyway when they ask you questions about the program.

      lol. thanks. best advice i've had all day. that's exactly what i did.
Re: 2 dimensional array
by GrandFather (Saint) on Jun 24, 2008 at 03:20 UTC

    The table of letters search is a nice little problem. You may like to ponder the following solution:

    use strict; use warnings; my $obj = bless {toDir => {qw(01 s 11 se 10 e 1-1 ne 0-1 n -1-1 nw -10 + w -11 s)}}; @{$obj}{'width', 'height'} = map {chomp; $_} split ',', <DATA>; for my $rowNum (1 .. $obj->{height}) { defined ($_ = <DATA>) or die "Fewer table rows than expected. Expected $obj->{height}, got +@{[$rowNum - 1]}"; chomp; push @{$obj->{table}}, [split '']; die "Short row given at row $rowNum" unless $obj->{width} == @{$ob +j->{table}[-1]}; } while (<DATA>) { chomp; push @{$obj->{wordList}}, split /,\s*/, uc; } for my $x (0 .. $obj->{width} - 1) { for my $y (0 .. $obj->{height} - 1) { $obj->explore ($x, $y); } } sub explore { my ($self, $x, $y) = @_; for my $word (@{$self->{wordList}}) { for my $xDelta (-1 .. 1) { for my $yDelta (-1 .. 1) { next if ! $xDelta and ! $yDelta; next unless $self->find ($word, $x, $y, $xDelta, $yDel +ta); my ($xPos, $yPos) = ($x + 1, $y + 1); print "Found '$word' starting at $xPos, $yPos and head +ing " . $self->{toDir}{"$xDelta$yDelta"} . "\n"; } } } } sub find { my ($self, $word, $x, $y, $xDelta, $yDelta) = @_; my $wordLen = length $word; return if $xDelta < 0 && $x - $wordLen < 0; return if $xDelta > 0 && $x + $wordLen >= $self->{width}; return if $yDelta < 0 && $y - $wordLen < 0; return if $yDelta > 0 && $y + $wordLen >= $self->{height}; return $self->search ($word, $x, $y, $xDelta, $yDelta) } sub search { my ($self, $word, $x, $y, $xDelta, $yDelta) = @_; my ($chr, $tail) = $word =~ /(.)(.*)/; my $tailLen = defined $tail ? length $tail : 0; return if $chr ne $self->{table}[$y][$x]; return 1 if $tailLen == 0; return $self->search ($tail, $x + $xDelta, $y + $yDelta, $xDelta, +$yDelta) } __DATA__ 15,10 ADESFJRASLXDFRT QBRAINOUEWHGYED RIRURLKUNGEASDV NAOBXCSTACHUIOL OJKDGKJGHJUINHR AHRHOAIDFSETRGH RXANOGSYEROGATS TOUDOGSDSAVFTRY UORTUOFRHRJUIKO BTIARTHYEUVFGQA Dogs, Cats Train

    Prints:

    Found 'DOGS' starting at 4, 5 and heading se Found 'DOGS' starting at 4, 8 and heading e Found 'CATS' starting at 10, 4 and heading w

    Unless you can explain one or two Perl idioms like @{[$rowNum - 1]} you would be smart not to try and pass this off as your own work. ;)


    Perl is environmentally friendly - it saves trees
      way over my head but thanks for the effort. fortunately, the objective of the problem was to test my algorithm writing ability, not my perl writing ability. :)