views:

116

answers:

5

I'm trying to iterate over a 2D array that is structured in this specific way. Whether or not this is a good way to structure the array is another question - I still need to be able to iterate over it (if it is possible).

@row1 = ( "Current Scan", "Last Month");
@row2 = ( "240", "0");
@row3 = ( "226", "209");
@row4 = ( "215", "207");

@array = (\@row1, \@row2, \@row3, \@row4);
print Dumper(@array);
printarray(@array);

Dumper gives me the following output:

$VAR1 = [
          'Current Scan',
          'Last Month'
        ];
$VAR2 = [
          '240',
          '0'
        ];
$VAR3 = [
          '226',
          '209'
        ];
$VAR4 = [
          '215',
          '207'
        ];

I've tried several for loops with no success. Each only prints the first row ($VAR1) and quits. Here is my most recent attempt:

sub printarray {
  @array = shift;
  $rowi = 0;
  foreach my $row (@array) {
    for (my $coli = 0; $coli <= @$row; $coli++) {
      print "$array[$rowi][$coli]\n";
    }
    $rowi++;
  }
}

I'm obviously overlooking something simple. What am I doing wrong? Thanks in advance!

+7  A: 

If you want just print the array, try following code:

foreach my $row (@array) {
   foreach my $elem (@$row) {
       print $elem; ## print elements without separator
   }
   print "\n"; ## new line after row
}

If you need indexes for some purpose, here we go:

for(my $row_i = 0; $row_i < @array; $row_i++) {
    for(my $column_i = 0; $column_i < @{ $array[$row_i] }; $column_i++) {
        print $array[$row_i][$column_i];
    }
}

The idea is that @array in scalar context returns number of elements in array. And @{ $array[$row_i] } is a little more tricky. It dereference array stored in $array[$row_i].

Update for subroutine:

In perl you can pass array by reference:

 printarray(\@array); ## pass reference

 sub printarray {
     my $array_ref = shift; ## no copy created

     foreach my $row (@$array_ref) { ## now we need to dereference
         ...
     }
 }

You can also pass a copy of array:

 printarray(@array);

 sub printarray {
     my @array_copy = @_; ## store local copy of array
     ...
 }

For more details take a look at How can I pass/return a {Function, FileHandle, Array, Hash, Method, Regex}? manual page.

And please add use strict; at the begining of programm. It'll force you to declare all variables, but will save bunch of time if you type something incorrectly.

Ivan Nevostruev
Thanks. I left out an even more important part above. I was so focused on the iteration portion that I forgot I had passed it through a subroutine... I think that's the problem.
Magicked
That did the trick. Thank you!
Magicked
+1  A: 
   #!/usr/bin/perl
   use warnings;
   use strict;

   my @row1 = ( "Current Scan", "Last Month");
   my @row2 = ( "240", "0");
   my @row3 = ( "226", "209");
   my @row4 = ( "215", "207");

   my @array = (\@row1, \@row2, \@row3, \@row4);

   foreach my $row (@array) {
     foreach my $value (@$row) {
        print "$value\n";
     }
   }

This will print

  Current Scan
  Last Month
  240
  0
  226
  209
  215
  207

Not sure if that's what you wanted.

Jonathan Swartz
+1  A: 

Yes, the problem is in the way you're passing the array to the subroutine. Perl flattens arrays in parameter lists. Basically, printarray(@array) is (in this example) equivalent to printarray($array[0], $array[1], $array[2], $array[3]). The shift at the beginning of printarray takes the first parameter and assigns it to @array. So no matter how big the array is, printarray only sees the first element.

cjm
+3  A: 

When you pass the array into the subroutine, you're essentially passing in eight scalars. Then, when you do

sub printarray {
  @array = shift;

... you're popping off only the first element in the list. Try:

sub printarray {
  @array = @_;
CanSpice
A: 

Are you looking for something like this:

#!/usr/bin/perl
use warnings;
use strict;
use Algorithm::Loops 'MapCar';

my @row1 = ( "Current Scan", "Last Month");
my @row2 = ( "240", "0");
my @row3 = ( "226", "209");
my @row4 = ( "215", "207");

my @array = (\@row1, \@row2, \@row3, \@row4);

MapCar { print "Scan: $_[0]: $_[1], $_[2], $_[3]\n" } @array;
ysth