As an exercise related to this problem (not solving the whole problem),
I wanted to find an algorithm for 'variations_with_repetitions', (algorithms not being my strong suit), and was able to find a solution. I wouldn't say it is pretty, but it works :-)
It doen't have an iterative solution. Instead it returns all the tuples.
#!/usr/bin/perl
use strict;
use warnings;
my $n = 3;
my @a = "a".."b";
my @b = vw_rep(\@a, $n); # variations with repetition (Algorithm::Comb
+inatorics)
use Data::Dump; dd \@b;
sub vw_rep {
my ($ref, $n) = @_;
my @c;
for my $k (0 .. $n-1) {
my $L = 0;
for (1 .. @$ref**$k) {
for my $i (0 .. $#$ref) {
for (1 .. @$ref**($n-1 - $k)) {
push @{ $c[$L++] }, $ref->[$i];
}
}
}
}
return @c;
}
__END__
C:\Old_Data\perlp>perl var_w_rep.pl
[
["a", "a", "a"],
["a", "a", "b"],
["a", "b", "a"],
["a", "b", "b"],
["b", "a", "a"],
["b", "a", "b"],
["b", "b", "a"],
["b", "b", "b"],
]
Update: A better approach using
choroba's solution in an iterative fashion could be:
#!/usr/bin/perl
use warnings;
use strict;
# Pm node 1211055
my $n = 3;
my @b = qw( a b );
my $iter = variations_rep_iter(\@b, $n);
while (my $tuple = $iter->()) {
print "@$tuple\n";
}
sub variations_rep_iter {
my ($bases, $n) = @_;
my @indices = (0) x $n;
my $first = 1;
my $iter = sub {
if ($first) {
$first = 0;
return [ @$bases[ @indices ] ];
}
my $r = $#indices;
while ($r >= 0) {
if (++$indices[$r] > $#$bases) {
$indices[$r--] = 0;
} else {
last
}
}
return if $r < 0;
return [ @$bases[ @indices ] ];
};
return $iter;
}