Magicked
Magicked

Reputation: 647

Perl: Iterating through this funky array?

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!

Upvotes: 1

Views: 2767

Answers (5)

ysth
ysth

Reputation: 98508

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;

Upvotes: 0

CanSpice
CanSpice

Reputation: 35828

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 = @_;

Upvotes: 3

cjm
cjm

Reputation: 62109

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.

Upvotes: 1

Ivan Nevostruev
Ivan Nevostruev

Reputation: 28753

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.

Upvotes: 10

Jonathan Swartz
Jonathan Swartz

Reputation: 1983

   #!/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.

Upvotes: 1

Related Questions