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

I've done some searches on permutations and combinations, but haven't quite found what I'm looking for.

Given the following:

my $params = [ 1, [ 2, 3, 4 ], 5, [ 6, 7, 8 ], 9 ];

I want arrays holding all the different combinations, in order of placement in the original params arrayref... e.g.
$output = [ [ 1, 2, 5, 6, 9 ], [ 1, 3, 5, 6, 9 ], [ 1, 4, 5, 6, 9 ], [ 1, 2, 5, 7, 9 ], [ 1, 3, 5, 7, 9 ], ... and so on


I'm sure I'll get it sooner or later, but I'm wondering what's a concise and generic way to do this, if anyone had any ideas (or is bored) :)
--------------
It's sad that a family can be torn apart by such a such a simple thing as a pack of wild dogs

Replies are listed 'Best First'.
Re: Permutations question
by kvale (Monsignor) on Feb 22, 2005 at 17:15 UTC
    Here is a solution based on tye's Algorithm::Loops:
    use Algorithm::Loops qw( NestedLoops ); my $iter= NestedLoops( [ [1], [ 2, 3, 4 ], [5], [ 6, 7, 8 ], [9] ], ); my @perms; while( @perms = $iter->() ) { print @perms, "\n"; }

    -Mark

      Or, if we want to exactly match the original request, it is easy to transform to:

      use Algorithm::Loops qw( NestedLoops ); sub expandSubLists { my $av= shift(@_); return [ NestedLoops( [ map ref($_) ? $_ : [$_], @$av ], sub { [@_] }, ), ]; }

      which, of course, chews up a lot of memory if given a lot of selections to generate.

      - tye        

Re: Permutations question
by Roy Johnson (Monsignor) on Feb 22, 2005 at 17:42 UTC
    Flattening things appropriately was the bugaboo.
    use strict; use warnings; use Data::Dumper; my $params = [ [ 2, 3, 4 ], 5, [ 6, 7, 8 ], 9 ]; sub get_numbers{ my $array = shift; my ($car, @cdr) = @$array; ref $car or $car = [$car]; @cdr or return $car; [ map { my $n = $_; map {[$n, (ref $_ ? @$_ : $_)] } @{get_numbers(\@cdr)}; } @$car ]; } print Dumper(get_numbers($params));

    Caution: Contents may have been coded under pressure.
      That does it... thanks !
      --------------
      It's sad that a family can be torn apart by such a such a simple thing as a pack of wild dogs
Re: Permutations question
by perlfan (Parson) on Feb 22, 2005 at 17:13 UTC
      The code there won't traverse arrayrefs (sub-arrayrefs) and lists permutations (my fault for bad wording in the title) - I need them in order. But it's a good place to start, so thanks!
      --------------
      It's sad that a family can be torn apart by such a such a simple thing as a pack of wild dogs
Re: Permutations question
by Roy Johnson (Monsignor) on Feb 22, 2005 at 19:14 UTC
    Here's a List::Util reduce solution that seg faults under 5.8.0 on Solaris, but works in ActiveState. :-)
    use strict; use warnings; use Data::Dumper; my $params = [ 1, [ 2, 3, 4 ], 5 ]; use List::Util 'reduce'; sub multiplex { reduce { my $aref = ref($a) ? $a : [[$a]]; my $bref = ref($b) ? $b : [$b]; [ map { my $b_item = $_; map [ @$_, $b_item], @$aref } @$bref ] ; } @{shift()}; } print Dumper(multiplex($params));
    And here's the same algorithm without reduce (and without seg faulting):
    sub multiplex { my $ret = [[]]; for (@{shift()}) { my $bref = ref($_) ? $_ : [$_]; $ret = [ map { my $b_item = $_; map [ @$_, $b_item], @$ret; } @$bref ]; } $ret; }

    Caution: Contents may have been coded under pressure.
      Note that using reduce seems to be a little bit faster.
      Nothing concerning, though.
      Rate no_reduce reduce no_reduce 42123/s -- -2% reduce 42955/s 2% --


      acid06
      perl -e "print pack('h*', 16369646), scalar reverse $="
Re: Permutations question
by blazar (Canon) on Feb 22, 2005 at 17:17 UTC
    I aplogize in advance if you already checked that, but did you try 'perldoc -q permute'? It contains some relevant information.
      Unfortunately the perldoc installation is incomplete on the UNIX machine I am using. I found it though, and am looking into it now - thanks!
      --------------
      It's sad that a family can be torn apart by such a such a simple thing as a pack of wild dogs
Re: Permutations question
by brian_d_foy (Abbot) on Feb 22, 2005 at 21:15 UTC

    A similar question was asked here earlier this week, and I suggested my module Set::CrossProduct. It's not the only module solution though.

    --
    brian d foy <bdfoy@cpan.org>
Re: Permutations question
by ambrus (Abbot) on Feb 22, 2005 at 17:40 UTC