File Coverage

blib/lib/List/Permute/Limit.pm
Criterion Covered Total %
statement 49 55 89.0
branch 11 16 68.7
condition 2 6 33.3
subroutine 7 7 100.0
pod 2 2 100.0
total 71 86 82.5


line stmt bran cond sub pod time code
1             package List::Permute::Limit;
2              
3             our $DATE = '2018-12-31'; # DATE
4             our $VERSION = '0.001'; # VERSION
5              
6 1     1   56563 use 5.010001;
  1         11  
7 1     1   10 use strict;
  1         3  
  1         27  
8 1     1   5 use warnings;
  1         1  
  1         26  
9              
10 1     1   4 use Exporter qw(import);
  1         1  
  1         424  
11             our @EXPORT_OK = qw(
12             permute
13             permute_iter
14             );
15              
16             our %SPEC;
17              
18             my %args_common = (
19             items => {
20             'x.name.is_plural' => 1,
21             'x.name.singular' => 'item',
22             schema => ['array*', min_len=>1],
23             req => 1,
24             pos => 0,
25             greedy => 1,
26             },
27             nitems => {
28             summary => 'Number of items of each permutation result',
29             schema => 'posint*',
30             },
31             );
32              
33             $SPEC{permute_iter} = {
34             v => 1.1,
35             args => {
36             %args_common,
37             },
38             result_naked => 1,
39             result => {
40             stream => 1,
41             },
42             };
43             sub permute_iter {
44 2     2 1 9 my %args = @_;
45 2         3 my $items = $args{items};
46 2 50 33     11 die "Please supply some items" unless $items && @$items;
47 2   33     6 my $nitems = int($args{nitems} // @$items);
48 2 50       5 die "Please supply a positive number of items (nitems)"
49             unless $nitems > 0;
50              
51 2         5 my $state = [(0) x $nitems];
52 2         3 my $state2 = 0; # 0,1,2
53             my $iter = sub {
54 34 100   34   97 if (!$state2) { # starting the first time, don't increment state yet
    50          
55 2         2 $state2 = 1;
56 2         8 goto L2;
57             } elsif ($state2 == 2) { # all permutation exhausted
58 0         0 return undef;
59             }
60 32         33 my $i = $#{$state};
  32         38  
61             L1:
62 32         48 while ($i >= 0) {
63 32 100       33 if ($state->[$i] >= $#{$items}) {
  32         40  
64 8 50       12 if ($i == 0) {
65 0         0 $state2 = 2;
66 0         0 return undef;
67             }
68 8         9 $state->[$i] = 0;
69 8         9 my $j = $i-1;
70 8         13 while ($j >= 0) {
71 8 100       8 if ($state->[$j] >= $#{$items}) {
  8         12  
72 2 50       3 if ($j == 0) { # all permutation exhausted
73 2         3 $state2 = 2;
74 2         5 return undef;
75             }
76 0         0 $state->[$j] = 0;
77 0         0 $j--;
78             } else {
79 6         6 $state->[$j]++;
80 6         8 last L1;
81             }
82             }
83 0         0 $i--;
84             } else {
85 24         24 $state->[$i]++;
86 24         25 last;
87             }
88             }
89             L2:
90 32         34 return [map { $items->[ $state->[$_] ] } 0..$#{$state}];
  64         116  
  32         44  
91 2         9 };
92 2         6 $iter;
93             }
94              
95             $SPEC{permute} = {
96             v => 1.1,
97             args => {
98             %args_common,
99             },
100             result_naked => 1,
101             };
102             sub permute {
103 1     1 1 92 my $p = permute_iter(@_);
104 1         1 my @res;
105 1         3 while (my $r = $p->()) { push @res, $r }
  16         28  
106 1         16 @res;
107             }
108              
109             1;
110             # ABSTRACT: Permute all items list, with limit of number of items per result item
111              
112             __END__