For testing purposes it is often useful to generate permutations on a list through an iterator (like tye's Derangements iterator. Sometimes we need random permutations, but for some applications it is necessary that there is an order in the generated permutations.

I am using the following order on permutations. If the list to be permuted consists of increasing digits, then the permutations are numbered such that the concatenated digits of each permutation would give monotonically increasing values.

Like that:

$ perl -w permute_n.pl 3 0: 1,2,3 1: 1,3,2 2: 2,1,3 3: 2,3,1 4: 3,1,2 5: 3,2,1

More control compared to an iterator is given by the 'random-access' permutation 'accessor' that can generate the n-th ordered permutation directly (thus 'random access').

For example you might want to use every n-th permutation or simply step backwards through the permutations. Maybe you are interested only in permutations on prime number positions...

For such purposes the following program allows flexible access. If the list of elements is large, it can avoid a lot wasteful calculating.

For example generate the first, third, fifth, and then the fifth last, third last, and the last permutation of the list of numbers 1..18:

$ perl -w permute_n.pl 18 0 2 4 -5 -3 -1 0: 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18 2: 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,17,16,18 4: 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,18,16,17 6402373705727995: 18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,1,3,2 6402373705727997: 18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,2,3,1 6402373705727999: 18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1

On the other hand, if all permutations are needed, any iterator would probably outperform this generator.

Enjoy.

#!/usr/bin/perl # # demo application for 'generate the n_th permutation of a list' # # permute_n [set_size [permutation_numbers]] # # parameters: # set_size # sets the size of the set to be used for permutation generation. # The set is built from numbers starting at 1. # # permutation_number # selects the permutation to be generated. # Negative values select from the end. # # defaults are: # set size=4 # (none)=generate all permutations # # The algorithm allows for 'random-access' generation of permutations. # In order to generate the last permutation, it is NOT necessary # to cycle through all preceeding permutations. # # (c) Heiko Eißfeldt, 2008 # use strict; use integer; use warnings; use bigint; my @object; my $size = shift || 4; my @perms = @ARGV; my $last = factorial($size); if (defined $perms[0]) { for my $n (@perms) { if ($n < 0) { $n += $last; } @object = (1..$size); permute_n($n, \@object); } } else { for my $which_permutation (0 .. $last - 1) { @object = (1..$size); permute_n($which_permutation, \@object); } } sub permute_n { my ($which_permutation, $object_ref) = @_; my $size = scalar @{$object_ref}; my $current_fac = factorial($size - 1); my $perm = $which_permutation; for my $level (reverse 2..$size) { my $offset = $size - $level; my $to_front = $perm / $current_fac; $perm = $perm % $current_fac; $current_fac = $current_fac / ($level-1); next if ($to_front == 0); # move position to front @{$object_ref}[$offset..$size-1] = ($object_ref->[$offset+$to_front], @{$object_ref}[$offset .. $offset+$to_front-1], @{$object_ref}[$offset+$to_front+1 .. $size-1], ); } print "$which_permutation: ", join(q{,}, @{$object_ref}), "\n" or +die "print $!\n"; return; } sub factorial { my ($n) = @_; my $result = 1; for my $fac (2..$n) { $result *= $fac; } return $result; }


In reply to a 'random-access' permutation generator by hexcoder

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.