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

Ok. I'm stumped. I've been trying to figure out a way of iterating through the various permutations of 1 through n and I can't. I've been trying to base this code on tye's Finding the Neighbors, but can't figure it out. Help?

------
We are the carpenters and bricklayers of the Information Age.

Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

Replies are listed 'Best First'.
(tye)Re: Iterating through permutations
by tye (Sage) on Mar 12, 2002 at 21:31 UTC

    Three clicks could have taken you to Permuting with duplicates and no memory. Now it will only require one. (:

    The link of mine that you originally linked to does what I usually think of as "counting" in a strange base (no, it isn't "combinations" in my book -- I'm curious what, if any, the official mathematical term for it is) and so would iterate through N**N cases, giving you many more than the N! cases you wanted.

    Since you don't need to avoid duplicates, you can probably do it more simply. The documentation for Algorithm::Permute has links to some good examples.

    ...Looking at Permuting with duplicates and no memory to see if there were any obvious improvements to be had if you assume no duplicates, I realized that I can change sort to reverse which should make it rather faster (while still handling duplicates). I'd compare it to Algorithm::Permute but that is all written in XS which makes it: 1) unfair, and 2) too hard to get running at the moment. Maybe later. (:

    Update: I compared the updated version of my code against the code that Algorithm::Permute includes in its sample benchmark code. My code beat all but the XS versions in speed (about 1/2 as fast as the XS version) and beat all of them in that my code handles duplicate items in the list while none of the others did. :)

            - tye (but my friends call me "Tye")
Re (tilly) 1: Iterating through permutations
by tilly (Archbishop) on Mar 12, 2002 at 22:27 UTC
    You can also go the inefficient but straightforward way, just everywhere use an iterator, and compose iterators to get new iterators. And, of course, iterators can be built out of closures. Try the following:
    sub ret_permute_iter { if (@_ < 2) { my @vals = ("garbage", @_); return sub { shift @vals; return @vals; }; } else { my ($cur, @left) = @_; my @done; my $iter = ret_permute_iter(@left); return sub { my @res = $iter->(); if (@res) { return ($cur, @res); } elsif (@left) { push @done, $cur; $cur = shift @left; $iter = ret_permute_iter(@done, @left); @res = $iter->(); return ($cur, @res); } else { return; } }; } } my $demo_iterator = ret_permute_iter(1..5); foreach (1..120) { print $demo_iterator->(), "\n"; }
    I won't compare speed to tye's because, um, I am much slower. :-) But you can arrive at this iterator approach from the standard list-based approach in a fairly mechanical fashion, and it is worthwhile figuring out how I did that.
Re: Iterating through permutations
by larsen (Parson) on Mar 12, 2002 at 20:27 UTC
    If you want to iterate on all the permutations of n elements, you could use Algorithm::Permute (which, IIRC, should contain even the code from Algorithm::FastPermute), with something like this (taken from docs):

    my @array = (1..9); Algorithm::Permute::permute { print "@array\n" } @array;

    The block of code is executed for every permutation.