in reply to Generating lists of strings

#! perl -slw use strict; sub nFor(&@) { my $code = shift; die "First argument must be a code ref" unless ref( $code ) eq 'CO +DE'; my @limits = @_; my @indices = ( 0 ) x @limits; for( my $i = $#limits; $i >= 0; ) { $i = $#limits; $code->( @indices ), ++$indices[ $i ] while $indices[ $i ] < $limits[ $i ]; $i = $#limits; $indices[ $i ] = 0, ++$indices[ --$i ] while $i >= 0 and $indices[ $i ] == $limits[ $i ]; } } my @digits = 1 .. 3; nFor { print join '', @digits[ @_ ]; } ( 3 ) x 4;

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.
"I'd rather go naked than blow up my ass"

Replies are listed 'Best First'.
Re^2: Generating lists of strings
by ikegami (Patriarch) on Jan 24, 2010 at 19:18 UTC

    That looks like a lot like the implementation of NestedLoop. Might as well use it.

    use Algorithm::Loops qw( NestedLoops ); my @digits = (1..3); NestedLoops( [ (\@digits) x 4 ], sub { print( @_, "\n" ); }, );

    Update: In addition to the above, this node originally said that BrowerUk's output was wrong and had code to fix the problem, but I was looking at a reply that produced incorrect output, not the OP. The incorrect version was removed.

      NestedLoop. Might as well use it.

      Your choice for your code. I much prefer the far simpler syntax of nFor.

      And, I think that the mirror between the syntax of nFor and the built-ins map & grep, makes my version far more familiar and digestable (though much less flexible), than the tortuous documentation for NestedLoops which I've still never wrapped by brain around.


      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.

        I much prefer the far simpler syntax of nFor.

        And nothing's stopping you from providing that interface.

        #! perl -slw use strict; use Algorithm::Loops qw( NestedLoops ); sub nFor(&@) { my $cb = shift; NestedLoops([ map [ 0..$_-1 ], @_ ], $cb); } my @digits = 1 .. 3; nFor { print join '', @digits[ @_ ]; } ( 3 ) x 4;

        than the tortuous documentation for NestedLoops which I've still never wrapped by brain around.

        Say you want

        apple, dog, 1 apple, dog, 2 apple, dog, III apple, cat, 1 apple, cat, 2 apple, cat, III apple, platypus, 1 apple, platypus, 2 apple, platypus, III orange, dog, 1 orange, dog, 2 orange, dog, III orange, cat, 1 orange, cat, 2 orange, cat, III orange, platypus, 1 orange, platypus, 2 orange, platypus, III tomato, dog, 1 tomato, dog, 2 tomato, dog, III tomato, cat, 1 tomato, cat, 2 tomato, cat, III tomato, platypus, 1 tomato, platypus, 2 tomato, platypus, III
        from
        # Variable number of lists of variable length my @lists = ( [qw( apple orange tomato )], [qw( dog cat platypus )], [qw( 1 2 III )], );

        That's what NestedLoops is for:

        local $, = ", "; local $\ = "\n"; NestedLoops(\@lists, sub { print @_ });

        nFor would require:

        local $, = ", "; local $\ = "\n"; nFor { print map $lists[$_][ $_[$_] ], 0..$#_; } map 0+@$_, @lists;

        Maybe you wouldn't have a problem understanding NestedLoops if it provided a map-ish interface?

        sub nested(&@) { my $cb = shift; NestedLoops(\@_, $cb); } local $, = ", "; local $\ = "\n"; nested { print @_; } @lists;

        Update: Switched initial line to something less rude.