Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

Multidimensional Arrays

by CharlesClarkson (Curate)
on Jun 22, 2001 at 11:11 UTC ( #90647=perltutorial: print w/ replies, xml ) Need Help??

Can any one explain me how to handle multidimensional array?

Well, let's just quickly review what an array is. An array is a variable that holds a list of scalar values.

    my @array = (1, 2, 3, 'four');

To access a single element of this array, we use a subscript. In perl a subscript is enclosed in square brackets [ ]. To print the first element of @array we write:

print $array[0]; ^

We use the scalar ($) prefix because we are referring to 1 value and we use a subscript of 0 because all arrays start with 0 as the first item (unless we change the value of mumble mumble mumble, which is deprecated).

Since an array can only hold a list of scalar values, it cannot hold an array (which is not a scalar) and multidimensional arrays are not possible in perl.

Let's take a short intermission here while we catch our breath.


This break is being sponsored by that wonderful little scalar - The Reference.

If you have done any assembler programming, you are familiar with indirect addressing. References are similar. (Okay, maybe not.) They allow us to refer to a scalar, array, hash, or any object indirectly.

What's more, they allow us to refer to these variables with a single scalar value. (Sort of like referring to a human as 'her' instead of 'that drop dead gorgeous blonde Gertrude Rose Bertrand'.)

Let's take a look at a reference to an array. To reference @array, we precede it with \:

my @array = (1, 2, 3, 'four'); my $reference = \@array; print $reference;
prints:
    ARRAY(0x1a6527c)

Note, that if we increase the size of @array by 1000 elements, the reference stays the same:

my @array = (1, 2, 3, 'four'); my $reference = \@array; print $reference; push @array, (1 .. 1000); $reference = \@array; print $reference;
prints:
    ARRAY(0x1a6527c)ARRAY(0x1a6527c)

We can refer to an element of an array reference with the arrow (->) notation:

my @array = (1, 2, 3, 'four'); my $reference = \@array; print $reference->[0];
prints:
    1

Oh another thing, a reference refers to the original variable, if you change an element in a reference you also change it the original variable or object which is sometimes referred to as the referent.

my @array = (1, 2, 3, 'four'); my $reference = \@array; $reference->[0] = 'one'; print "@array";
prints:
    one 2 3 four
(*disclaimer:
all variables in the preceding examples
are fictitious. Any resemblance to real
variables is purely coincidental. References
will not be directly (or indirectly) liable for
any similarities to real variables.)

This preceding break was sponsored by that wonderful little scalar - The Reference.


Well, now that your finished buying your popcorn and staring at that drop dead gorgeous blonde Gertrude Rose Bertrand. Let's look at a way to have multidimensional arrays and still use perl.

You may want to read a little about references before continuing. Perlref has some stuff in it you'll find useful. (I'm far to busy to mention them here!)

Since a reference is a scalar and an array holds a list of scalars, an array could hold a list references. Now, an array reference can refer to an element of the array it refers to with the arrow notation (->) just like we did with @array before the intermission.

Let's review:
my @array = (1, 2, 3, 'four'); print $array[0];
prints:     1
my @array = (1, 2, 3, 'four'); my $reference = \@array; print $reference->[0];
prints:
    1
And for more than one dimension:
my @array1 = (1, 2, 3, 'four'); my $reference1 = \@array1; my @array2 = ('one', 'two', 'three', 4); my $reference2 = \@array2; my @array = ($reference1, $reference2); # this refers to the first item of the first array: print $array[0]->[0];
prints:
    1

Okay. $array[0] refers to $reference1 and a reference to an array can use arrow notation to refer to it's elements.

$reference1->[0] refers to @array1's first element. Using a little algebra we can replace like terms. $reference1 = $array[0], so $reference1->[0] is the same as $array[0]->[0].

(Please, take a moment to write a nice email to your under appreciated algebra teacher. We'll wait for you.)

You wrote to Gertrude, didn't you? (Shame!)

Let's take a look at a reference to an array that has no name. A nameless array is (drum roll, please) anonymous. An anonymous array in perl is constructed using square brackets [ ].

Named:
my @array1 = (1, 2, 3, 'four'); my $reference1 = \@array1;
Anonymous:
    my $reference1 = [1, 2, 3, 'four'];
So we could rewrite:
my @array1 = (1, 2, 3, 'four'); my $reference1 = \@array1; my @array2 = ('one', 'two', 'three', 4); my $reference2 = \@array2; my @array = ($reference1, $reference2); print $array[0]->[0];
As:
my @array = ( [1, 2, 3, 'four'], ['one', 'two', 'three', 4] ); print $array[0]->[0];
prints:
    1
"Trust in the Algebra, Luke"

Perl allows us to drop the -> between subscripts, so we can also write this as:

my @array = ([1, 2, 3, 'four'], ['one', 'two', 'three', 4]); print $array[0][0];
prints:     1

Perldsc has a section titled 'ARRAYS OF ARRAYS' that gives more examples of declaring and generating an array of array references (a.k.a. multidimensional arrays). Note that an array can contain references to arrays of differing sizes:

my @shapes = ( [qw/circle square triangle polygon/], [qw/red green blue yellow fuschia/] );

Data::Dumper provides a the Dumper sub which will print an array of array references. This is a great debugging tool:

use Data::Dumper; print Dumper \@shapes;

Here's the output one array:

$VAR1 = [ [ 'circle', 'square', 'triangle', 'polygon' ], [ 'red', 'green', 'blue', 'yellow', 'fuschia' ] ];

Finally, take a look at Perllol which describes Manipulating Arrays of Arrays in Perl and Perldata, especially the part about slices (and apple pie).




"The only dumb question is the one you fail to ask."

Update (2 FEB 2009): Fixed a typo and changed array name.

Update (5 JUN 2012): Added missing code tags around Data::Dumper code.

Comment on Multidimensional Arrays
Select or Download Code
Re: Multidimensional Arrays
by chipmunk (Parson) on Jun 22, 2001 at 20:18 UTC
    The syntax @array->[0] is unsupported; it was never really intended to work in the first place.

    The perldelta that comes with 5.6.1 explains:

    Arrow operator and arrays When the left argument to the arrow operator "->" is an array, or the "scalar" operator operating on an array, the result of the operation must be considered erroneous. For example: @x->[2] scalar(@x)->[2] These expressions will get run-time errors in some future release of Perl.
    I think that your tutorial is somewhat misleading, because you seem to suggest that @array->[0] is a standard idiom.

      Well, I haven't gotten aroud to installing 5.6.1 and I probably would have missed this. Would you mind rereading the tutorial. I edited it with your comment in mind and would like to know if it screwed up the logical flow.


      Thank You,
      Charles
        great tutorial. I was really struggling trying to grasp the concept, I had read everything I could, but nothing seemed to sink in until I read this article! Charles, you have a gift. I almost did not read the article due to the name, perhaps you could mention reference. I wish some of the posts on why NOT to use symbolic references had a link to this article... Another intersting chapter might be using hashes in a reference.
Re: Multidimensional Arrays
by Anonymous Monk on Mar 18, 2003 at 22:21 UTC
    I hate to pick nits...no, wait. I love to pick nits. Well, nevermind then. What I mean is, to be accurate, "Using a little algebra we can replace like terms." is incorrect. $reference1 and $array[0[]] aren't like terms at all, they're entirely different variables. They *are* equal terms. Maybe we should email *your* algebra teacher... :)

    Hey! Are you even listening? Hello? Oh, put the picture down already!
Re: Multidimensional Arrays
by Anonymous Monk on May 28, 2003 at 07:47 UTC
    Beautiful description. I too have tried over and over to learn this. I ended up creating a moc multi-dimentional array with a hash:

     $qa{"Q1.A3"} ="Question 1, Answer 3"; # dbl Quotes required!

    I can iterate through the array answers for Q1 like this:

       for $i (1..5) print $qa{"Q1.A$i"} . '\n';

    As an added benefit, I can also create other "properties":

      $qa{"Q1.type"} = "radio";

    So, that makes it sort of like a virtual object, which I need to learn someday. This was great. Thanks again. -sleve

Re: Multidimensional Arrays
by vili (Monk) on Jul 22, 2003 at 23:58 UTC
    Useful, and to the point.
    Thanks fo taking the time.
    ~vili
Re: Multidimensional Arrays
by Sameet (Beadle) on Apr 30, 2004 at 06:25 UTC
    Hi, I am a newbie, and this node was surely very useful. Thank you
    Sameet

      You're welcome. Glad you liked it.


      Charles
Re: Multidimensional Arrays
by Anonymous Monk on Aug 25, 2004 at 02:19 UTC
    Thanks for this tutorial, a quick google search lead me to this page. Got the answer I needed faster than by searching the perl docs.

    I was trying...
    @array[0] = ("a","b","c");
    but that didn't work.
    What I needed was
    @array[0] = ["a","b","c"];
    so that I can read a value directly with
    $value = $array[$y][$x];

    Thanks again.

Re: Multidimensional Arrays
by Anonymous Monk on Oct 14, 2004 at 06:27 UTC
    Apart from having the drop dead looks, you also write very well. Your tutorials gives a good picture of arrays in arrays and the difference between arrays using () and []. Thanks Kasp
Re: Multidimensional Arrays
by Anonymous Monk on Nov 25, 2004 at 09:29 UTC
    my @row0 = (1, 0, 0); my @row1 = (0, 1, 0); my @row2 = (0, 0, 1); my @arr = ( \@row0, \@row1, \@row2 ); for ( $i = 0; $i < 3; $i++ ) { for ( $j = 0; $j < 3; $j++ ) { print "arr[$i][$j] = $arr[$i][$j]\n"; } } # works perfectly print "*" x 80, "\n"; my @another = \$arr[1]; for ( $i = 0; $i < 3; $i++ ) { print "another[$i] = $another->[$i]\n"; } # while this loop prints blanks
    what am i doing wrong ?
      You could try:
      my @another = @{$arr[1]}; for ( $i = 0; $i < 3; $i++ ) { print "another[$i] = $another[$i]\n"; }
      using an array to hold the row, or:
      my $another = $arr[1]; for ( $i = 0; $i < 3; $i++ ) { print "another[$i] = $another->[$i]\n"; }
      using a ref to the row. You should also consider use strict;, BTW...
      my @another = \$arr[1];

      @another has a single element - a reference to a reference to an array.

      Try:

      ${${$another[0]}}[$i]

      Update: fixed typo

        This works, too:
        @{${$another[0]}}[$i]
        I think ist is a little bit clearer (from in to out): 1. fetch array element 0, 2. dereference, 3. treat it like an array, 4. fetch via [$i].

        But this all looks really ugly. It would be better to fix the strange assignment to @another than to use such a complicated expression just to fetch a value...

Re: Multidimensional Arrays
by sapnac (Beadle) on Jul 06, 2005 at 19:16 UTC
    Thanks Charles
    This really well written and clears the concept

    Keep up the good work

    Sapna
Re: Multidimensional Arrays
by Anonymous Monk on Oct 21, 2008 at 02:15 UTC
    Hi and thanks for the great tutorial...one small note use Data::Dumper; print Dumper \@array; should be... use Data::Dumper; print Dumper \@shapes; Thanks again
Re: Multidimensional Arrays
by czyker (Initiate) on Sep 19, 2011 at 18:34 UTC
    Thank you SO much. Finally an explanation that makes sense. This is absolutely outstanding.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perltutorial [id://90647]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others surveying the Monastery: (9)
As of 2014-09-24 05:54 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    How do you remember the number of days in each month?











    Results (246 votes), past polls