Perl: Using Algorithm::Loops
for-loop, perl
Solution
You are making this harder than it has to be. Part of the problem is that the documentation for NestedLoops doesn't go into much detail about how a subroutine reference in the first argument, will be used.
For the following examples, assume this is written somewhere above them.
use strict;
use warnings;
use Algorithm::Loops qw'NestedLoops';
Really the simplest way to call NestedLoops to get what you want is like this:
NestedLoops(
[
['a'..'e'],
['f'..'j'],
['k'..'o'],
],
\&permute
);
sub permute {
print @_, "\n";
}
If you really want the arguments to NestedLoops to be generated on the fly, I would recommend using part from List::MoreUtils.
use List::MoreUtils qw'part';
my @a = 'a'..'o';
my $length = 5;
my $index;
NestedLoops(
[
part {
$index++ / $length
} @a
],
\&permute
);
sub permute {
print @_, "\n";
}
If for some reason you want to call NestedLoops with indexes into the array, It is still easy with part.
use List::MoreUtils qw'part';
my @a = 'a'..'o';
my $length = 5;
NestedLoops(
[
part {
$_ / $length
} 0..@a-1
],
\&permute
);
sub permute {
print map { $a[$_] } @_;
print "\n";
}
Really the main problem you're having is that the two subroutine references that you give to NestedLoops are modifying the same variables, and they are both called multiple times. The best way to fix this is to rely on the last value given to the subroutine when it is called. ( From looking at the implementation, this seems to be closer to how it was meant to be used. )
my @a = 'a'..'o';
my $length = 5;
my $depth = 3;
NestedLoops(
[
[0..$length-1],
(sub{
return unless @_;
my $last = pop;
my $part = int( $last / $length ) + 1; # current partition
my $start = $part * $length; # start of this partition
my $end = $start + $length;
[$start..$end-1] # list of variables in this partition
}) x ($depth-1)
],
\&permute
);
sub permute {
print map { $a[$_] } @_;
print "\n";
}
Problem
I'm trying to construct a permutation program in Perl using the NestedLoops function. Here's my code: ``` use strict; use warnings; use Algorithm::Loops qw(NestedLoops); my @a = 'a'..'o'; my $length = 5; my $start = 0; my $depth = 2; NestedLoops([ [0..$length], ( sub { $start = 0 if $start == $depth; $start++; [$start * $length..$start * $length + $length - 1] }) x $depth, ], \&permute,); sub permute { my @ind = @_; foreach my $i (@ind) { print $a[$i]; } print "\n"; } ``` So I've got an array that holds the letters 'a' to 'o' (size being 15). I'm treating the array as if it had 3 rows, so my imagination of the array is this: ``` abcde fghij klmno ``` Then each loop corresponds to each row... and I want to build permutations like: ``` afk afl afm afn afo agk // fails here... I end up getting agg ... ``` It works for the first 5 values (the entire run of the lowest for loop), but then the second run fails because the last row's value of `$start` gets reset to 0... this is a problem because that breaks everything. So what I want to know is, how can I keep the value of `$start` persistent based on the level... So what I'm asking for is essentially having constants. My loops really should look like this: ``` for my $a (0..5) { # 0 at this level and never change for my $b (5..10) { # $start should be 5 at this level and never change for my $c (10..15) { # $start should be 10 at this level and never change permute($a, $b, $c); } } } ``` Now, because I will have a variable length of for loops, I can't hard code each start value, so I'm looking for a way to initially create those start values, and then keep them for when the loop gets reset. I realize this is a confusing question, so please ask questions, and I will help clarify.