File Coverage

blib/lib/Iterator/Misc.pm
Criterion Covered Total %
statement 63 63 100.0
branch 19 24 79.1
condition 10 15 66.6
subroutine 15 15 100.0
pod 5 5 100.0
total 112 122 91.8


line stmt bran cond sub pod time code
1             =for gpg
2             -----BEGIN PGP SIGNED MESSAGE-----
3             Hash: SHA1
4              
5             =head1 NAME
6              
7             Iterator::Misc - Miscellaneous iterator functions.
8              
9             =head1 VERSION
10              
11             This documentation describes version 0.03 of Iterator::Misc, August 26, 2005.
12              
13             =cut
14              
15 6     6   156715 use strict;
  6         13  
  6         246  
16 6     6   30 use warnings;
  6         11  
  6         307  
17             package Iterator::Misc;
18             our $VERSION = '0.03';
19              
20 6     6   48 use base 'Exporter';
  6         28  
  6         688  
21 6     6   30 use vars qw/@EXPORT @EXPORT_OK %EXPORT_TAGS/;
  6         10  
  6         753  
22              
23             @EXPORT = qw(ipermute igeometric inth irand_nth ifibonacci);
24             @EXPORT_OK = @EXPORT;
25              
26 6     6   5040 use Iterator;
  6         114811  
  6         10363  
27              
28             # Function name: ipermute
29             # Synopsis: $iter = ipermute (@items);
30             # Description: Generates permutations of a list.
31             # Created: 07/29/2005 by EJR
32             # Parameters: @items - the items to be permuted.
33             # Returns: Sequence iterator
34             # Exceptions: Iterator::X::Am_Now_Exhausted
35             # Notes: Algorithm from MJD's book.
36             sub ipermute
37             {
38 2     2 1 24 my @items = @_;
39 2         10 my @digits = (0) x @items; # "Odometer". See Dominus, pp 128-135.
40              
41             return Iterator->new (sub
42             {
43 14 100   14   9369 unless (@digits)
44             {
45 2         10 Iterator::is_done;
46             }
47              
48             # Use the existing state to create a new permutation
49 12         19 my @perm = ();
50 12         26 my @c_items = @items;
51 12         63 push @perm, splice(@c_items, $_, 1) for @digits;
52              
53             # Find the rightmost column that isn't already maximum
54 12         21 my $column = $#digits;
55 12   66     72 until ($digits[$column] < $#digits-$column || $column < 0)
56 20         67 { $column-- }
57              
58 12 100       24 if ($column < 0)
59             {
60             # Last set. Generate no more.
61 2         5 @digits = ();
62             }
63             else
64             {
65             # Increment the rightmost column; set colums to the right to zeroes
66 10         12 $digits[$column]++;
67 10         41 $digits[$_] = 0 for ($column+1 .. $#digits);
68             }
69              
70 12         64 return \@perm;
71 2         34 });
72             }
73              
74              
75             # Function name: ifibonacci
76             # Synopsis: $iter = ifibonacci ($start1, $start2);
77             # Description: Generates a Fibonacci sequence.
78             # Created: 07/27/2005 by EJR
79             # Parameters: $start1 - First starting value
80             # $start2 - Second starting value
81             # Returns: Sequence iterator
82             # Exceptions: Iterator::X::Am_Now_Exhausted
83             # Notes: If $start2 is omitted, $start1 is used for both.
84             # If both are omitted, 1 is used for both.
85             sub ifibonacci
86             {
87 3 50   3 1 2949 my ($start1, $start2) = @_ == 0? (1, 1)
    100          
    100          
88             : @_ == 1? ($_[0], $_[0])
89             : @_ == 2? @_
90             : Iterator::X::Parameter_Error->throw
91             ("Too many arguments to ifibonacci");
92              
93             return Iterator->new( sub
94             {
95 33     33   608 my $retval;
96 33         58 ($retval, $start1, $start2) = ($start1, $start2, $start1+$start2);
97 33         101 return $retval;
98 3         21 });
99             }
100              
101             # Function name: igeometric
102             # Synopsis: $iter = igeometric ($start, $end, $factor);
103             # Description: Generates a geometric sequence.
104             # Created: 07/28/2005 by EJR
105             # Parameters: $start - Starting value
106             # $end - Ending value
107             # $factor - multiplier.
108             # Returns: Sequence iterator
109             # Exceptions: Iterator::X::Am_Now_Exhausted
110             # Notes: If $end if omitted, series is unbounded.
111             # $factor must be specified.
112             sub igeometric
113             {
114 8     8 1 16016 my ($start, $end, $factor) = @_;
115 8         24 my $growing = abs($factor) >= 1;
116              
117             return Iterator->new (sub
118             {
119 44 100 66 44   1208 Iterator::is_done
      66        
120             if (defined $end && ($growing && $start > $end || !$growing && $start < $end));
121              
122 41         53 my $retval = $start;
123 41         45 $start *= $factor;
124 41         180 return $retval;
125 8         62 });
126             }
127              
128             # Function name: inth
129             # Synopsis: $iter = inth ($n, $iter)
130             # Description: Returns 1 out of every $n items.
131             # Created: 07/29/2005 by EJR
132             # Parameters: $n - frequency
133             # $iter - other iterator
134             # Returns: Sequence iterator
135             # Exceptions: Iterator::X::Parameter_Error
136             # Iterator::X::Am_Now_Exhausted
137             sub inth
138             {
139 2     2 1 1366 my $n1 = -1 + shift;
140 2         3 my $iter = shift;
141              
142 2 100       18 Iterator::X::Parameter_Error->throw('Invalid "$n" value for inth')
143             if $n1 < 0;
144              
145 1 50       5 Iterator::X::Parameter_Error->throw
146             (q{Second parameter for inth must be an Iterator})
147             unless UNIVERSAL::isa($iter, 'Iterator');
148              
149             return Iterator->new (sub
150             {
151 6     6   136 my $i = $n1;
152 6   66     25 while ($i-->0 && $iter->isnt_exhausted)
153             {
154 24         415 $iter->value(); # discard value
155             }
156              
157             Iterator::is_done
158 6 50       168 if $iter->is_exhausted;
159              
160 6         35 return $iter->value();
161 1         7 });
162             }
163              
164             # Function name: irand_nth
165             # Synopsis: $iter = irand_nth ($n, $iter)
166             # Description: Returns 1 out of every $n items, randomly.
167             # Created: 07/29/2005 by EJR
168             # Parameters: $n - frequency
169             # $iter - other iterator
170             # Returns: Sequence iterator
171             # Exceptions: Iterator::X::Parameter_Error
172             # Iterator::X::Am_Now_Exhausted
173             sub irand_nth
174             {
175 2     2 1 1403 my $n = shift;
176 2         3 my $iter = shift;
177              
178 2 100       17 Iterator::X::Parameter_Error->throw('Invalid "$n" value for inth')
179             if $n <= 0;
180              
181 1 50       5 Iterator::X::Parameter_Error->throw
182             (q{Second parameter for irand_nth must be an Iterator})
183             unless UNIVERSAL::isa($iter, 'Iterator');
184              
185 1         3 my $prob = 1 / $n;
186              
187             return Iterator->new (sub
188             {
189 6   66 6   259 while (rand > $prob && $iter->isnt_exhausted)
190             {
191 19         402 $iter->value(); # discard value
192             }
193              
194             Iterator::is_done
195 6 50       86 if $iter->is_exhausted;
196              
197 6         46 return $iter->value();
198 1         7 });
199             }
200              
201              
202             1;
203             __END__