Here's a version you can add to Algorithm::Loops. It uses NestedLoops and is comparatively efficient about skipping invalid combinations. It also puts its results in numeric/lexicographic order and handles duplicates. The commented-out code is for watching/debugging the management of the "pool" of available numbers.
use strict;
use warnings;
use Algorithm::Loops 'NestedLoops';
sub derange {
# Generate the list of possible values at each position
# Skip a value if it's already used up (no more in the pool) or is i
+n its original position
my %pool;
++$pool{$_} for (@_);
my @orig = @_;
no warnings 'numeric';
my @values = sort {$a <=> $b or $a cmp $b} keys %pool;
my @prev_values;
NestedLoops(
[(sub {
# Generate all candidate values for this position
# print "Generating with \@_ = @_\n";
my $pos = @_;
# Update the pool: the last value on @_ has just changed, so
# return the previous value(s) to the pool and remove the new
# one.
if (@_) {
for (grep {defined $prev_values[$_]} $#_..$#orig-1) {
#print "Returning $prev_values[$_] to the pool\n";
++$pool{$prev_values[$_]};
undef $prev_values[$_];
}
#print "Removing $_[-1] from the pool\n";
--$pool{$_[-1]};
#print "Valid values in the pool:\n";
#while (my ($k,$v) = each %pool) {
# print "$k: $v\n" if $v;
#}
$prev_values[$#_] = $_[-1];
}
[ grep {$orig[$pos] ne $_ and $pool{$_} > 0} @values ]
}) x @orig]
);
}
my @results;
my $iter = derange(@ARGV);
print "@results\n" while @results = $iter->();
As a possibly interesting note: if you simply remove $orig[$pos] ne $_ and, it becomes a permutations generator. But derange is not simply a permutations generator that filters out individual invalid permutations; it prunes entire sub-trees. (Similarly, the permutation generator doesn't loop through the whole cartesian space and filter it.)
Caution: Contents may have been coded under pressure.
-
Are you posting in the right place? Check out Where do I post X? to know for sure.
-
Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
<code> <a> <b> <big>
<blockquote> <br /> <dd>
<dl> <dt> <em> <font>
<h1> <h2> <h3> <h4>
<h5> <h6> <hr /> <i>
<li> <nbsp> <ol> <p>
<small> <strike> <strong>
<sub> <sup> <table>
<td> <th> <tr> <tt>
<u> <ul>
-
Snippets of code should be wrapped in
<code> tags not
<pre> tags. In fact, <pre>
tags should generally be avoided. If they must
be used, extreme care should be
taken to ensure that their contents do not
have long lines (<70 chars), in order to prevent
horizontal scrolling (and possible janitor
intervention).
-
Want more info? How to link
or How to display code and escape characters
are good places to start.
|