ozboomer has asked for the wisdom of the Perl Monks concerning the following question:

'lo again...

I've been trying to find an algorithm to produce all the permutations for a subset of a group of items.

I've searched through my books, the web, all my code and have not found anything useful. I've searched this site and have found many articles that discuss the process in general... but these discussions nearly exclusively talk about various modifications to Algorithm::Permute, which is not suitable, as it says in the documentation: "...Currently it only supports permutation n of n objects", which is not what I want to do.

An almost trivial task at present, I have a group of 5 objects, from which I'm selecting 2 items at a time (5P2). I can do the calculation and work out there are 20 combinations but I'd like to implement an algorithm that builds the list of permutations, e.g. AB, AC, AD, AE, BA, BC, BD, etc. It's when the master set of objects gets to nearly 100 that manually building the 9900 permutations will become horrendous :)

If anyone can provide some clues, I'd appreciate it greatly.

John

Replies are listed 'Best First'.
Re: Searching for a Permutation Algorithm for nPr where n != r (A::Loops)
by tye (Sage) on Apr 26, 2004 at 15:03 UTC

    Algorithm::Loops makes this pretty easy:

    #!/usr/bin/perl -w use strict; use Algorithm::Loops qw( NestedLoops ); my @items= ( 1..6 ); my $choose= 3; my $iter= NestedLoops( [ [ 0..$#items ], ( sub { [ $_+1 .. $#items ] } ) x ($choose-1), ], ); my @choice; while( @choice= @items[$iter->()] ) { print "@choice\n"; # replace above line with your code }

    produces

    1 2 3 1 2 4 1 2 5 1 2 6 1 3 4 1 3 5 1 3 6 1 4 5 1 4 6 1 5 6 2 3 4 2 3 5 2 3 6 2 4 5 2 4 6 2 5 6 3 4 5 3 4 6 3 5 6 4 5 6

    - tye        

      The OP wanted permutations, not just combinations:
      e.g. AB, AC, AD, AE, BA, BC, BD, ...

      -QM
      --
      Quantum Mechanics: The dreams stuff is made of

        I missed that "BA" in the list. The last page of Algorithm::Loops talks specifically about this problem and shows a few ways to do it. A fairly minor update to my code is one such way:

        #!/usr/bin/perl -w use strict; use Algorithm::Loops qw( NestedLoops NextPermute ); my @items= ( 1..5 ); my $choose= 2; my $iter= NestedLoops( [ [ 0..$#items ], ( sub { [ $_+1 .. $#items ] } ) x ($choose-1), ], ); my @choice; while( @choice= @items[$iter->()] ) { do { print "@choice\n"; # replace above line with your code } while( NextPermute(@choice) ); }

        produces

        1 2 2 1 1 3 3 1 1 4 4 1 1 5 5 1 2 3 3 2 2 4 4 2 2 5 5 2 3 4 4 3 3 5 5 3 4 5 5 4

        - tye        

Re: Searching for a Permutation Algorithm for nPr where n != r
by ambrus (Abbot) on Apr 26, 2004 at 14:00 UTC

    I suggest a recursive approach. While this might not be the fastest one, it is easy to write:

    sub vari { my ($set,$num,$act)= @_; my(%h,$rec,@s); $h{$_}= 0 for @$set; $rec= sub { $_[0] or return $act->(@s); $h{$_} or do { local $h{$_}= 1; push @s, $_; $rec->($_[0]-1); pop @s; } for @$set; }; $rec->($num); } vari [qw{a b c d e f g}], 3, sub { print join(" ",@_), $/; };

    Update: changed code to be stable.

Re: Searching for a Permutation Algorithm for nPr where n != r
by Thelonius (Priest) on Apr 26, 2004 at 13:43 UTC
    What you need to do is generate each combination of r items out of n, and for each subset generated, generate all permutations of it.

    You may find useful help in the forthcoming volume of Knuth's The Art of Computer Programming. Knuth has preprints of parts of it on his web site. You'll need a postscript viewer (or printer) to look at them.

    I transcribed one of the non-recursive permutation algorithms into Perl here.

Re: Searching for a Permutation Algorithm for nPr where n != r
by exussum0 (Vicar) on Apr 26, 2004 at 11:05 UTC
    I don't have my text book in front of me, but this can be seen as a graphing problem.

    Take N items and put them in a fully connected complete graph. Everything is connected to everything. What you are asking for is all paths of length 2, in the case of nP2 I believe it's an n^3'd problem involving three for loops (update, i thought it was two, but my heart says 3).

    If you don't have to store all of your text somewhere, you can probably derive the letters by their indicies (i=0 is the same as i=A, i=1 is the same as i=B).

    It's not a solution, but if you take a look at some graphing algorithm chapters, it may give you some ideas.

Re: Searching for a Permutation Algorithm for nPr where n != r
by kvale (Monsignor) on Apr 26, 2004 at 15:34 UTC
    If you are only choosing two elements at a time, a simple solution may be best:
    my @arr = (1..100); foreach my $i (0..@arr-1) { foreach my $j (0..@arr-1) { next if $i == $j; print "$arr[$i],$arr[$j]\n"; } }
    if r > 3 or so, tye's solution is good for more general cases.

    -Mark