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

Fellow monks, I kindly request your assistance... Am I going blind or insane, probably both... I've been at this for the past 2 hours, looking at various bits of code, but I can not get a multidimensional array assigned or referenced as a single dimension. This example is supposed to output Jan, Feb, Mar, but doesn't do that.. What am I doing wrong? I have been able to make it work with for loops, but that kinda defeats the purpose, since I'm trying to reference the column for join as well. Thanks for your assistance.

#!/usr/bin/perl @ary = ( ['Jan', 10, 20], ['Feb', 15, 25], ['Mar', 30, 33]); foreach $f (@ary[0]) { print "==> $f\n"; }

Replies are listed 'Best First'.
Re: Multi dimentions to a single dimentional array
by ikegami (Patriarch) on Jan 23, 2010 at 06:33 UTC

    There isn't really such a thing as a multi-dimensional array in Perl. You have what is called "array of arrays", which is short for "array of array references".

    In this case, @ary contains three array references. You want something from each referenced array, so you need to visit each reference:

    for my $month_data (@ary) { ... }

    Now you need to extract the first element of the array referenced by $month_data:

    $month_data->[0]

    All together:

    for my $month_data (@ary) { print $month_data->[0], "\n"; }
Re: Multi dimentions to a single dimentional array
by biohisham (Priest) on Jan 23, 2010 at 06:23 UTC
    You're not going blind nor insane but your mission is half-way through, cheers, your multi-dimensional array has been assigned and built successfully, for each element in the dimension referenced you need to appropriately dereference it to be able to access it...

    When you loop through the first dimension you'd be looping through anonymous arrays as elements of that dimension hence $f would refer to an anonymous array, dereferencing that anonymous array using the infix arrow operator would enable you access its elements in turn too..

    use strict; use warnings; my @ary = ( #First Dimension ['Jan', 10, 20], #second Dimension ['Feb', 15, 25], ['Mar', 30, 33] ); foreach my $f (@ary) { print "==> $f->[0]\n"; #infix Arrow Operator dereferencing.. #print "==> @{$f}[0]\n"; #another way of dereferencing too..(T +ry It) }

    Update: You can still achieve the same through indexing in a for loop, here are some of the different ways this is possible:

    for (my $i=0;$i<=$#ary; $i++){ print "==>$ary[$i][0]\n"; # print "==>@{$ary[$i]}[0]\n"; # print "==>$ary[$i]->[0]\n"; }

    It's worthwhile investing time in reading Perl data structure cookbook, manipulating arrays of arrays in Perl, References Tutorial and the Monastery's very own tutorials on the subject at References...


    Excellence is an Endeavor of Persistence. Chance Favors a Prepared Mind.
Re: Multi dimentions to a single dimentional array
by rubasov (Friar) on Jan 23, 2010 at 12:54 UTC
    biohisham and ikegami explained cleanly how you can reference the elements in the first "column" one-by-one in a for loop. If you want to join these elements, you can extend that idiom like this (by storing the values in a new array called @column):
    use strict; use warnings; my @AoA = ( [ 'Jan', 10, 20 ], [ 'Feb', 15, 25 ], [ 'Mar', 30, 33 ] ); my @column; for my $month_data (@AoA) { push @column, $month_data->[0]; } print join( ' ', @column ), "\n";
    However you can use shorter and cleaner constructs, if you don't need them one-by-one, but all of them at once, as an array for the "column". Try this:
    use strict; use warnings; my @AoA = ( [ 'Jan', 10, 20 ], [ 'Feb', 15, 25 ], [ 'Mar', 30, 33 ] ); print join( ' ', map {$_->[0]} @AoA ), "\n"; # prints 'Jan Feb Mar' print join( ' ', map {$_->[1]} @AoA ), "\n"; # prints '10 15 30'
    The map expression above (map {$_->[0]} @AoA) creates and returns a new array by implicitly iterating through your array refs ("lines", $AoA[0], $AoA[1] ...), taking the first element ("column", $AoA[0][0], $AoA[1][0] ...) from each and constructing the new array from them. (But of course, if you think this is too much for once, just stick with the first and easier version.)
Re: Multi dimentions to a single dimentional array
by toolic (Bishop) on Jan 23, 2010 at 13:51 UTC
    Tip #1 from the Basic debugging checklist is to use diagnostics. This would have given you a couple of hints as to the specific problems with your misbehaving code, particularly to look into how references work.

    Tip #4 is also useful in visualizing your data structure, using Data::Dumper.

Re: Multi dimentions to a single dimentional array
by jpm493 (Initiate) on Jan 24, 2010 at 19:12 UTC
    Like ikegami said, The array you created contains 3 scalars. Each scalar is really a reference to an array. Multi-dimensional arrays do not really exist; perl does allow arrays of arrays which is what you have created and which requires slightly more complex inspection.

    Seems like you have to skim the first item from each inner array and the previous posts have done a good job of posting solutions.