http://www.perlmonks.org?node_id=1222715

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

Couldn't find the answer to this anywhere, but it should be a fairly simple question for an expert (which I am not).

If I have an array @x, that I have, say, initialized up to $x[5][11], is there some way of looping over the rows (and then the columns within each row) without setting up the classic for loops with counters such as $i and $j? I read somewhere that if you are using counters in perl, you are not doing it right, so I am wondering about other syntax (foreach?) that might do that.

Replies are listed 'Best First'.
Re: looping over multidimensional arrays
by LanX (Archbishop) on Sep 20, 2018 at 14:35 UTC
    for my $a1 (@x) { for my $a2 (@$a1) { for my $a3 (@$a2) { ... # hope you get the pattern by now } } }

    For covering arbitrary depth of nesting you could apply a recursive function (a so called "walker")

    If the elements are other than array_refs you might want to add cases after testing ref $aX.

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

Re: looping over multidimensional arrays
by Marshall (Abbot) on Sep 20, 2018 at 15:42 UTC
    I hope this code is of help...
    A multi-dimensional array is built by making arrays of references to array. You don't get to the actual data until the last dimension.
    Here I explicitly build a 2D structure, what is called an AoA (Array of Array).
    #!/usr/bin/perl use strict; use warnings; use Data::Dump qw(pp); my @row1 = qw(a b c); my @row2 = qw(d e f); my @AoA = (\@row1, \@row2); pp \@AoA; # [["a", "b", "c"], ["d", "e", "f"]] foreach my $my_row_ref (@AoA) { print "@$my_row_ref \n"; } #a b c #d e f print "$AoA[1][1]\n"; #prints "e" #print column1... foreach my $my_row_ref (@AoA) { print "$my_row_ref->[1] \n"; } #b #e
Re: looping over multidimensional arrays
by AnomalousMonk (Bishop) on Sep 20, 2018 at 16:57 UTC

    Another approach using array slices.

    c:\@Work\Perl\monks>perl -wMstrict -MData::Dump -le "my @AoA = ( [ '00' .. '09' ], [ '10' .. '19' ], [ '20' .. '29' ], [ '30' .. '39' ], ); dd \@AoA; ;; print join '-', @{ $AoA[1] }[ 3 .. 7 ]; print qq{@{ $AoA[2] }[ 2 .. 5 ]}; " [ ["00", "01", "02", "03", "04", "05", "06", "07", "08", "09"], [10, 11, 12, 13, 14, 15, 16, 17, 18, 19], [20, 21, 22, 23, 24, 25, 26, 27, 28, 29], [30, 31, 32, 33, 34, 35, 36, 37, 38, 39], ] 13-14-15-16-17 22 23 24 25
    See also Perl Data Structures Cookbook.


    Give a man a fish:  <%-{-{-{-<

Re: looping over multidimensional arrays
by BillKSmith (Prior) on Sep 20, 2018 at 20:12 UTC
    You can usually replace the innermost loop with a map.
    ?type 1222715.pl use strict; use warnings; use Data::Dumper; my @array = ( [qw(0a 0b 0c 0d 0e 0f 0g 0h 0i 0j 0k)], [qw(1a 1b 1c 1d 1e 1f 1g 1h 1i 1j 1k)], [qw(2a 2b 2c 2d 2e 2f 2g 2h 2i 2j 2k)], [qw(3a 3b 3c 3d 3e 3f 3g 3h 3i 3j 3k)], [qw(4a 4b 4c 4d 4e 4f 4g 4h 4i 4j 4k)], ); my @array_new; foreach my $vec (@array) { push @array_new, [map {myfunc($_)} @$vec]; } print Dumper(\@array_new); sub myfunc { return "$_[0]_new"; } ?perl 1222715.pl $VAR1 = [ [ '0a_new', '0b_new', '0c_new', '0d_new', '0e_new', '0f_new', '0g_new', '0h_new', '0i_new', '0j_new', '0k_new' ], [ '1a_new', '1b_new', '1c_new', '1d_new', '1e_new', '1f_new', '1g_new', '1h_new', '1i_new', '1j_new', '1k_new' ], ... ]; ?
    Bill
Re: looping over multidimensional arrays
by haukex (Chancellor) on Sep 23, 2018 at 08:02 UTC
    I read somewhere that if you are using counters in perl, you are not doing it right

    That's probably a bit of an exaggeration to make a point: People coming from other languages will be used to C-style for loops, but often Perl's foreach will do away with a need to use indicies in the first place.

    But sometimes you need an index, and there, instead of for (my $i; $i<@a; $i++), the more Perlish ways are for my $i (0..$#a) or, on newer versions of Perl, you can use each.

    Note: This is a re-post of a node that was lost.

Re: looping over multidimensional arrays
by Laurent_R (Canon) on Sep 20, 2018 at 21:24 UTC
    See also the answers to this post for additional solutions and information: Joining array into new string

    This is an example with map, shown here at the command line:

    $ perl -we 'use strict; > use Data::Dumper; > my @AoA = ( ["a" .. "d"], ["e" .. "h"]); > print Dumper \@AoA; > print "\n", map { "@$_ "} @AoA;' $VAR1 = [ [ 'a', 'b', 'c', 'd' ], [ 'e', 'f', 'g', 'h' ] ]; a b c d e f g h