File Coverage

blib/lib/Math/Permute/Lists.pm
Criterion Covered Total %
statement 61 61 100.0
branch 12 12 100.0
condition 3 3 100.0
subroutine 9 9 100.0
pod 1 2 50.0
total 86 87 98.8


line stmt bran cond sub pod time code
1             =head1 Name
2            
3             Math::Permute::Lists - Generate all the permutations of zero or more nested lists.
4            
5             =head1 Synopsis
6            
7             use Math::Permute::Lists;
8            
9             permute {say "@_"} [1,2],[3,4];
10            
11             # 1 2 3 4
12             # 1 2 4 3
13             # 2 1 3 4
14             # 2 1 4 3
15             # 3 4 1 2
16             # 3 4 2 1
17             # 4 3 1 2
18             # 4 3 2 1
19            
20             permute {say "@_"} 1,[2,[3,4]];
21            
22             # 1 2 3 4
23             # 1 2 4 3
24             # 1 3 4 2
25             # 1 4 3 2
26             # 2 3 4 1
27             # 2 4 3 1
28             # 3 4 2 1
29             # 4 3 2 1
30            
31             =cut
32            
33 12     12   192162 use strict;
  12         23  
  12         625  
34            
35             package Math::Permute::Lists;
36            
37 12     12   54 use warnings FATAL => qw(all);
  12         17  
  12         483  
38 12     12   46 use strict;
  12         15  
  12         5048  
39            
40 24     24 0 2680 sub permute(&@) # Generate permutations of lists - user interface
41             {my $s = shift; # Subroutine to call to process each permutation
42 24         73 &Permute($s, undef, @_); # Perform permutations
43             }
44            
45             sub Permute # Generate and expand permutations - private
46 162     162 1 145 {my $S = shift; # User subroutine to call to process each permutation
47 162         129 my $R = shift; # Subroutine to expand replacements
48            
49 162         169 my $Single = __PACKAGE__.'Single'; # User supplied item
50 162         127 my $Expand = __PACKAGE__.'Expand'; # Sub permutations of user items
51 162     162   117 my $mirror; $mirror = sub # Mirror permutation structure
  162         126  
52             {my @p; # Items to be permuted discovered at this level
53 162         198 for(@_)
  43         129  
54 297 100 100     870 {if (ref eq "ARRAY" or ref eq $Expand) # Array of sub items to be permuted together
55 254         665 {push @p, bless [0, bless $_, $Expand], $Single; # Not in use, sublist
56             }
57             else # A single item
58             {push @p, bless [0, $_], $Single; # Not in use, user item
59             }
60             }
61             @p # Result
62 162         366 };
  162         286  
63            
64 162         237 my $M = [&$mirror(@_)]; # Mirrors the user supplied permutation structure but with additional data
65 162         182 my @Q = (); # Permuted array = output area
66 162         121 my $N = 0; # Number of permutations encountered
67            
68 162     1171   117 my $replace; $replace = sub # Replace sub permutations with their expansions
  1171         1356  
69             {my @q = @_; # Fully or partially expanded row
70 1171 100       930 if (grep {ref($_) eq $Expand} @q) # Check whether results if fully expanded yet
  6286         6551  
  138         98  
71 1033         695 {my @p; # Prefix elements that are fully expanded
72 138         212 for(;@q;) # Remove leading block of items that do not need expansion
  405         333  
73             {my $q = shift @q; # Each element, leaving trailing elements
74 405 100       461 if (ref($q) ne $Expand) # Leading expanded elements
  267         395  
75 248         361 {push @p, $q; # Save leading expanded element
76             }
77             else # First element requiring expansion
78 138         419 {&Permute($S, sub {&$replace(@p, @_, @q);}, @$q); # Expand sub permutation and use it to expand the current row
79 138         278 return;
80             }
81             }
82             }
83             else # Fully expanded - call user processing routine
84             {++$N; # Number of permutations encountered
85 1033         1307 &$S(@q); # Pass to user
86             }
87 162         406 };
88            
89 162         134 my $permute; $permute = sub # Generate permutations
  5634         6197  
90 3101 100   3101   4237 {if (scalar(@Q) == scalar(@$M)) # Row has been generated when it has enough elements
91 1171 100       1006 {($R ? $R : $replace)->(map {$_->[1]} @Q); # Subsequent or first replacement of user data
92 1170         2863 return;
93             }
94            
95 1930         1569 my ($P) = @_; # Permutations to be performed
96 1930         1843 for my $p(@$P) # Find an item that has not been used so far in this permutation
  2939         2233  
97 9547 100       13250 {if (!$p->[0]) # Not in use
98             {push @Q, $p; # Place it in the next position in the output area
99 2939         2239 $p->[0] = 1; # Mark it as in use
100 2939         3432 &$permute($P); # Choose again
101 2937         2457 $p->[0] = 0; # Mark it as available
102 2937         2848 pop @Q; # Free space in output area
103             }
104             }
105 162         320 };
106            
107 162         216 &$permute($M); # Permute per user
108 161         170 $mirror = $replace = $permute = undef; # Break memory cycles
109 161         1588 $N # Return number of permutations performed
110             }
111            
112             # Export details
113            
114             require 5;
115             require Exporter;
116            
117 12     12   64 use vars qw(@ISA @EXPORT $VERSION);
  12         27  
  12         1236  
118            
119             @ISA = qw(Exporter);
120             @EXPORT = qw(permute);
121             $VERSION = '1.001';
122            
123             =head1 Description
124            
125             Generate all the permutations of zero or more nested lists using the standard
126             Perl metaphor.
127            
128             C returns the number of permutations in both scalar and array
129             context.
130            
131             C is 100% Pure Perl.
132            
133             =head1 Export
134            
135             The C function is exported.
136            
137             =head1 Installation
138            
139             Standard Module::Build process for building and installing modules:
140            
141             perl Build.PL
142             ./Build
143             ./Build test
144             ./Build install
145            
146             Or, if you're on a platform (like DOS or Windows) that doesn't require
147             the "./" notation, you can do this:
148            
149             perl Build.PL
150             Build
151             Build test
152             Build install
153            
154             =head1 Author
155            
156             PhilipRBrenan@appaapps.com
157            
158             http://www.appaapps.com
159            
160             =head1 Acknowledgements
161            
162             From a suggestion by Philipp Rumpf.
163            
164             =head1 See Also
165            
166             =over
167            
168             =item L
169            
170             =item L
171            
172             =item L
173            
174             =item L
175            
176             =item L
177            
178             =item L
179            
180             =back
181            
182             =head1 Copyright
183            
184             Copyright (c) 2009 Philip R Brenan.
185            
186             This module is free software. It may be used, redistributed and/or
187             modified under the same terms as Perl itself.
188            
189             =cut