Skip to content

Instantly share code, notes, and snippets.

@grondilu
Last active December 14, 2015 21:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save grondilu/18a2f01d76677de1a7e3 to your computer and use it in GitHub Desktop.
Save grondilu/18a2f01d76677de1a7e3 to your computer and use it in GitHub Desktop.
permutations with NQP code
use nqp;
sub permutations(int $n where $n > 0) {
Seq.new:
class :: does Iterator {
# See: L<https://en.wikipedia.org/wiki/Permutation#Generationn_lexicographic_order>
has int $!n;
has Mu $!permutation;
submethod BUILD(:$n) { $!n = $n; $!permutation := nqp::list(); self }
#method is-lazy { True }
method pull-one {
unless nqp::elems($!permutation) {
my int $i = -1;
nqp::bindpos($!permutation, $i, +$i) while ++$i < $!n;
return nqp::clone($!permutation);
}
# Find the largest index k such that a[k] < a[k + 1].
# If no such index exists, the permutation is the last permutation.
my int $k = $!n - 2;
$k-- or return IterationEnd until nqp::atpos($!permutation, $k) < nqp::atpos($!permutation, $k + 1);
# Find the largest index l greater than k such that a[k] < a[l].
my int $l = $!n - 1;
$l-- until nqp::atpos($!permutation, $k) < nqp::atpos($!permutation, $l);
# use L<https://en.wikipedia.org/wiki/XOR_swap_algorithm>
# @!permutation[$k, $l].=reverse
nqp::bindpos($!permutation, $k, nqp::bitxor_i(nqp::atpos($!permutation, $k), nqp::atpos($!permutation, $l)));
nqp::bindpos($!permutation, $l, nqp::bitxor_i(nqp::atpos($!permutation, $k), nqp::atpos($!permutation, $l)));
nqp::bindpos($!permutation, $k, nqp::bitxor_i(nqp::atpos($!permutation, $k), nqp::atpos($!permutation, $l)));
# @!permutation[$k+1 .. @!permutation.end].=reverse;
$l = $!n;
until ++$k >= --$l {
nqp::bindpos($!permutation, $k, nqp::bitxor_i(nqp::atpos($!permutation, $k), nqp::atpos($!permutation, $l)));
nqp::bindpos($!permutation, $l, nqp::bitxor_i(nqp::atpos($!permutation, $k), nqp::atpos($!permutation, $l)));
nqp::bindpos($!permutation, $k, nqp::bitxor_i(nqp::atpos($!permutation, $k), nqp::atpos($!permutation, $l)));
}
return nqp::clone($!permutation);
}
method count-only { [*] 1 .. $!n }
}.new(:$n)
}
.say for permutations(6);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment