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

Hi, new to perl...
I want to define a N-dimensional array of fixed dimensions, and then pass it to a subroutine with other variables.
How do I define that array and pass it to/from the subroutine?
I do not understand if the shift operator can recognise the array among the variables passed, and if the dimensions are kept with the shift-extracted array... maybe I have to pass its dimensions to have them available in the subroutine?
This in Fortran :) would be, for example:
PARAMETER (NX=10,NY=10) REAL A(NX,NY) ..... CALL S1(A,NX,NY) ..... END SUBROUTINE S1(B,I,K) REAL B(I,K) ... RETURN END
thanx...

Replies are listed 'Best First'.
Re: dimensioning arrays
by eg (Friar) on Feb 16, 2001 at 15:35 UTC

    You'll want to read perldata, perllol and perldsc (and maybe perlref and perlreftut for good measure :)

    What you'll want to do is make a reference to a list of a list (of a list of a list ... etc.) For example:

    my $array_1 = [ 1, 2, 3 ]; # 1d my $array_2 = [ [1, 2, 3], [1, 2, 3], [1, 2, 3] ]; #2d my $array_3 = [ [ [1, 2, 3], [1, 2, 3], [1, 2, 3] ], [ [1, 2, 3], [1, 2, 3], [1, 2, 3] ], [ [1, 2, 3], [1, 2, 3], [1, 2, 3] ], ]; # 3d ... etc.

    which can be extended to however many dimensions you want. Using an array ref makes things easy because you can just pass $array_1, $array_2, $array_3 around as you would any ol' scalar. A specific cell in your n-dimensional array can be referenced as:

    $array_1->[$x]; $array_2->[$x][$y]; $array_3->[$x][$y][$z]; ... etc.

    Or, by "fixed dimensions" do you mean that your n-dimensional array is of a pre-determined size? In that case you can always use the old trick of storing everything in a single array with a pre-declared length and calculating every element's position (see your favorite algorithms/data structures book for details.)

    update: I forgot to mention, if your n-dimensional array is sparsely populated, you might look into using a hash and "multidimensional array emulation".

    my %array = (); $array{$x1,$y1,$z1} = something; $array{$x2,$y2,$z2} = something else; ...

    Obviously this is Terribly Bad if you need to loop around your array and, frankly, I've never had much use for this, but I thought I should bring it up in case it happens to work for you ...

Re: dimensioning arrays
by davorg (Chancellor) on Feb 16, 2001 at 15:25 UTC

    You can't define a Perl array to have certain number of dimensions, or a certain number of elements. This is because of a (generally very useful) feature called autovivification. This means that you could just write code like:

    my @arr; $arr[0][1][2][3] = 4;

    And suddenly you have a four dimensional array where the first dimension has one element, the second two and so on. The element that you haven't given values to will have the special value undef.

    And as for passing multidimensional structures like this to a subroutine, you're better off doing it with references. See perlreftut, perllol and perldsc for more details.

    --
    <http://www.dave.org.uk>

    "Perl makes the fun jobs fun
    and the boring jobs bearable" - me

Re: dimensioning arrays
by zigster (Hermit) on Feb 16, 2001 at 15:29 UTC
    Perl does not directly support multidimensional arrays, you need to create such complex structures using references. So you in effect create an array of references to other arrays. As to howto define this:
    @TDArray = (["Flange", "Widget"], ["Gerbal","Twaddle]); #Prints Flange print $TDArray[0][0];
    Checkout Chapter 4 of the cammel book for more information or array of arrays or perlman:perllol.
    HTH
    --

    Zigster
Re (tilly) 1: dimensioning arrays
by tilly (Archbishop) on Feb 16, 2001 at 17:13 UTC
    If you want high performance you may also want to look at PDL.
Re: dimensioning arrays
by Gloom (Monk) on Feb 16, 2001 at 15:41 UTC
    There's no fixed dimensions for perl's array : they are dynamicly extensible.
    You can pre-allocate an amount of elements by playing with the $#array value ( see camel's book for more details ).

    You can get the number of elements in an array by invoke it in a scalar context. exemple :
    $count = @array; or $count = scalar @array;

    Update

    Too late ... there's already many responses more sharp ... So scuse me ( and my poor english :) and forget this node.

    --------------------------------
    Hope this helps
Re: dimensioning arrays
by Anonymous Monk on Feb 16, 2001 at 16:17 UTC
    hi, after your replies (thanks) I'm thinking about this:
    #/usr/bin/perl $nx=10; $ny=5; $initialisation = 0; foreach $i (0..$nx) { foreach $j (0..$ny) { $a[$i][$j] = $initialisation; } } $a[1][1] = 2; &subro($nx,\@a,$ny); sub subro($nx,\@a,$ny) { my $nx = shift; my @a = @{shift}; #should be wrong... my $ny = shift; print "$a[1][1]\n"; print "$nx\n"; print "$ny\n"; }
    I saw the @{shift} use in some node around, but I get an error...
    How do i fix it?
    rob
      @{shift} may means @{'shift'} or @shift : it's ambiguous.

      be more sharp by adding "()" after shift.
      ... my $nx = shift; my @a = @{shift()}; # This should resolve your problem my $ny = shift; ...
      ________________________
      Hope this helps
        Thanks, Now it works.
        It would be nice for me to have a general subroutine
        sub initialise(\@dimensions,$initialisation_value,\@matrix)
        that gives back an initalised matrix of n-dimensions. I'll try as learning exercise, if it is not straightforward for someone to write it down here. There's a lot to learn from a snippet of code..:)
        rob