File Coverage

blib/lib/List/NSect.pm
Criterion Covered Total %
statement 36 36 100.0
branch 16 16 100.0
condition 9 9 100.0
subroutine 10 10 100.0
pod 3 3 100.0
total 74 74 100.0


line stmt bran cond sub pod time code
1             package List::NSect;
2 6     6   193248 use strict;
  6         13  
  6         249  
3 6     6   34 use warnings;
  6         13  
  6         193  
4 6     6   30 use base qw{Exporter};
  6         14  
  6         737  
5 6     6   5837 use List::MoreUtils qw{part};
  6         11098  
  6         2970  
6              
7             our $VERSION = '0.06';
8             our @EXPORT = qw(nsect);
9             our @EXPORT_OK = qw(spart deal);
10              
11             =for stopwords natatime nsect
12              
13             =head1 NAME
14              
15             List::NSect - Cuts or divides a list into N equal parts.
16              
17             =head1 SYNOPSIS
18              
19             use List::NSect;
20             my @sections=nsect(5 => "a" .. "z");
21             foreach my $section (@sections) {
22             print join(",", @$section), "\n";
23             }
24              
25             Output
26              
27             a,b,c,d,e,f
28             g,h,i,j,k
29             l,m,n,o,p
30             q,r,s,t,u
31             v,w,x,y,z
32              
33             =head1 DESCRIPTION
34              
35             List::NSect is an L that exports the function "nsect".
36              
37             =head2 nsect like bisect not mosquito
38              
39             I had a hard time deciding on a function name that was distinct and succinct. When I searched the Internet for "divide into equal parts", "bisect - to divide into two equal parts" was one of the top hits. I then tried to find a synonym for "divide into N equal parts". I soon realized that there is no single English word for the concept: thus "nsect".
40              
41             Other function names that I was contemplating are "chunk" (to cut, break, or form into chunks), "allot" (to divide or distribute by share or portion) and "apportion" (to distribute or allocate proportionally; divide and assign according to some rule of proportional distribution). None of these names implies the need for exactly N sections instead of some other distribution.
42              
43             I use this capability all of the time which is a specific implementation of List::MoreUtils::part. You may ask `why not just use "part" directly from L?` Well, there are many edge cases. Please, take a look at the code; This is Perl!
44              
45             =head1 USAGE
46              
47             use List::NSect;
48             my @sections=nsect($n => @list); #returns ([...], [...], [...], ...); #$n count of arrray references
49              
50             use List::NSect qw{spart};
51             my @batches=spart($n => @list); #returns ([...], [...], [...], ...); #array reference of $n size
52              
53             =head1 FUNCTION
54              
55             =head2 nsect
56              
57             Cuts or divides a list into N equal or nearly equal parts.
58              
59             Returns an array of array references given a scalar number of sections and a list.
60              
61             my @sections=nsect(4, 1 .. 17); #returns ([1,2,3,4,5],[6,7,8,9],[10,11,12,13],[14,15,16,17]);
62             my $sections=nsect(4, 1 .. 17); #returns [[1,2,3,4,5],[6,7,8,9],[10,11,12,13],[14,15,16,17]];
63              
64             =cut
65              
66             sub nsect {
67 28   100 28 1 84806 my $n = shift || 0;
68 28         55 my $count = scalar(@_);
69 28         47 my @sections = ();
70             #undef, 0 or empty array returns nothing as requested
71 28 100 100     147 if ($n > 0 and $count > 0) {
72 8 100       30 $n=$count if $n > $count;
73 8         12 my $i=0;
74 8     52   101 @sections=part {int($i++ * $n / $count)} @_; #Each partition created is a reference to an array.
  52         129  
75             }
76 28 100       7426 return wantarray ? @sections : \@sections;
77             }
78              
79             =head2 spart (not exported by default)
80              
81             Cut or divides a list into parts each of size N.
82              
83             Returns an array of array references given a scalar size and a list.
84              
85             my @parts=spart(4, 1 .. 17); #returns ([1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16],[17]);
86             my $parts=spart(4, 1 .. 17); #returns [[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16],[17]];
87              
88             Note: The last array reference may be short.
89              
90             =cut
91              
92             sub spart {
93 28   100 28 1 115306 my $parts = shift || 0;
94 28         52 my @deck = ();
95             #undef, 0 or empty array returns nothing as requested
96 28 100       71 if ($parts > 0) {
97 16         24 my $i = 0;
98 16     52   128 @deck = part {int($i++ / $parts)} @_; #/#Each partition created is a reference to an array.
  52         108  
99             }
100 28 100       139 return wantarray ? @deck : \@deck;
101             }
102              
103             =head2 deal (not exported by default)
104              
105             Deals a list into hands
106              
107             Returns an array of array references given a scalar size and a list.
108              
109             my @hands=deal(4, 1 .. 17); #returns ([1,5,9,13,17],[2,6,10,14],[3,7,11,15],[4,8,12,16]);
110              
111             =cut
112              
113             sub deal {
114 28   100 28 1 68485 my $hands = shift || 0;
115 28         57 my @deck = ();
116             #undef, 0 or empty array returns nothing as requested
117 28 100       192 if ($hands > 0) {
118 16         23 my $hand = 0;
119 16 100   52   149 @deck=part {$hand=0 if $hand>=$hands; $hand++;} @_;
  52         109  
  52         91  
120             }
121 28 100       162 return wantarray ? @deck : \@deck;
122             }
123              
124             =head1 LIMITATIONS
125              
126             my @sections=nsect($n => @list);
127              
128             The nsect function will ALWAYS return an array (array reference in scalar context). So, that you can always pass the return directly into a foreach loop without the need to test for edge cases. However, I made the executive decision that if $n > scalar(@list) the returned array, @sections, is not $n in size but rather scalar(@list) in size.
129              
130             my @sections=nsect(100, "a", "b", "c"); #scalar(@sections) == 3 != 100;
131              
132             =head1 BUGS
133              
134             Please log on RT and send an email to the author.
135              
136             =head1 SUPPORT
137              
138             DavisNetworks.com supports all Perl applications including this package.
139              
140             =head1 AUTHOR
141              
142             Michael R. Davis
143             CPAN ID: MRDVT
144             Satellite Tracking of People, LLC
145             mdavis@stopllc.com
146             http://www.stopllc.com/
147              
148             =head1 COPYRIGHT
149              
150             This program is free software licensed under the...
151              
152             The General Public License (GPL) Version 2, June 1991
153              
154             The full text of the license can be found in the LICENSE file included with this module.
155              
156             =head1 SEE ALSO
157              
158             L part and natatime, L, L, L, L
159              
160             =cut
161              
162             1;