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

What's the easiest way to write a loop over an n-dimensional lattice?

It's the kind of thing where I'd use nested for loops if I knew ahead of time how many dimensions I needed, but for a variable number of dimensions I can't set a level of nesting directly in the code.

Pointers in the right direction would be much obliged.

Replies are listed 'Best First'.
Re: loop over n-dimensional lattice (cpan)
by tye (Sage) on Aug 05, 2008 at 05:46 UTC

    Algorithm::Loops::NestedLoops(). That will also give you more keywords in case you want to search for any of the several threads here at PerlMonks that discuss how the code in the module or similar code can be written.

    - tye        

      I appreciate the help. Thanks!
Re: loop over n-dimensional lattice
by BrowserUk (Patriarch) on Aug 05, 2008 at 08:35 UTC
      To clarify-- It looks to me like the A::L::NestedLoops method lets me execute code directly within the nested loops where the List::Comprehensions method lets me generate a list of parameter values that I would then feed into my function as a second step. Do I have that right?

        No. A::L::NestLoops provides an iterator; List::Comprehensions takes a callback.

        By way of example, you mentioned iterating an N-dimensional 'lattice', (by which I assume you mean 'array'), that you don't know how many dimensions it will have until runtime. If you run the following code it will select a 2,3, or 4 dimension array at random and then iterate it printing out the indices and values:

        #! perl -slw use strict; use List::Comprehensions; sub expandDims { return unless ref $_[ 0 ] eq 'ARRAY'; return [ 0 .. $#{ $_[ 0 ] } ], expandDims( $_[ 0 ][ 0 ] ); } my $ref2D = [ map [ 0 .. 2 ], 0..3 ]; my $ref3D = [ map [ map [ 0..1 ], 0..2, ], 0..3 ]; my $ref4D = [ map [ map [ map [ 0..1 ], 0..2, ], 0..3 ], 0..4 ]; my $ref = ( $ref2D, $ref3D, $ref4D )[ rand 3 ]; comp1 { my $val = $ref; $val = $val->[ $_ ] for @_; printf "[%s] := %s\n", join('][', @_), $val; } expandDims( $ref );

        The output looks like this:

        c:\test>junk4 [0][0] := 0 [0][1] := 1 [0][2] := 2 [1][0] := 0 [1][1] := 1 [1][2] := 2 [2][0] := 0 [2][1] := 1 [2][2] := 2 [3][0] := 0 [3][1] := 1 [3][2] := 2 c:\test>junk4 [0][0][0] := 0 [0][0][1] := 1 [0][1][0] := 0 [0][1][1] := 1 [0][2][0] := 0 [0][2][1] := 1 [1][0][0] := 0 ... [3][0][0] := 0 [3][0][1] := 1 [3][1][0] := 0 [3][1][1] := 1 [3][2][0] := 0 [3][2][1] := 1 c:\test>junk4 [0][0][0][0] := 0 [0][0][0][1] := 1 [0][0][1][0] := 0 [0][0][1][1] := 1 [0][0][2][0] := 0 ... [4][3][0][0] := 0 [4][3][0][1] := 1 [4][3][1][0] := 0 [4][3][1][1] := 1 [4][3][2][0] := 0 [4][3][2][1] := 1

        Not very interesting, but it demonstrates both discovering the dimensions of the AoA(...) at runtime and then iterating it.

        There is a flaw in L::C, relative to FP language equivalents. Namely, that although it will accept multiple 'guard' subs interspersed with the array refs as input, the guard sub are called en-masses with all the generated arguments just prior to the main callback. In (for example) Haskell, the guard subs are called in their input order with just the arguments that precede (right to left) them in the input list.

        The advantage of A::Ls iterator is that you can abandon the iterator at any time, where L::Cs callback will be called for the entire set of combinations. Though you can suppress entry to the main callback by returning nothing from a guard sub. For example, if you change last line of the code above to this:

        } sub{ "@_" =~ /2/ ? () : @_ }, expandDims( $ref );

        Then the main callback code will not be called if any of the indices is a 2. For the 2D array, the output then becomes:

        c:\test>junk4 [0][0] := 0 [0][1] := 1 [1][0] := 0 [1][1] := 1 [3][0] := 0 [3][1] := 1

        The main advantage (for me) of L::C is that I find the syntax more amenable to the way I think.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.