File Coverage

blib/lib/List/Bisect.pm
Criterion Covered Total %
statement 29 30 96.6
branch 8 8 100.0
condition n/a
subroutine 6 6 100.0
pod 2 2 100.0
total 45 46 97.8


line stmt bran cond sub pod time code
1             package List::Bisect;
2             BEGIN {
3 1     1   23155 $List::Bisect::VERSION = '0.002';
4             }
5 1     1   9 use strict;
  1         3  
  1         36  
6 1     1   4 use warnings;
  1         2  
  1         38  
7 1     1   9 use Exporter qw{import};
  1         2  
  1         451  
8             our @EXPORT = qw{bisect trisect};
9              
10             # ABSTRACT: split a list in to two parts by way of a grep like block
11              
12             =head1 EXPORTED FUNCTION
13              
14             =head2 bisect
15              
16             my ($a,$b) = bisect {$_ <= 5} 1..10;
17             # $a == [1..5]
18             # $b == [6..10]
19              
20             Useage is like grep where you pass it a block and a list, returns a list of two arrayrefs. All
21             TRUE values are put in to the first arrayref, FALSE in the second arrayref.
22              
23             =cut
24              
25             sub bisect (&@) {
26 1     1 1 24 my $grep = shift;
27              
28 1         1 my @true;
29             my @false;
30 1         3 foreach $_ (@_) {
31 10 100       16 if (&$grep) {
32 5         16 push @true, $_;
33             }
34             else {
35 5         16 push @false, $_;
36             }
37             }
38              
39 1         4 return (\@true,\@false);
40             }
41              
42             =head2 trisect
43              
44             my ($a,$b,$c) = trisect {$_ <=> 5} 1..10;
45             # $a == [1..4]
46             # $b == [5]
47             # $c == [6..10]
48              
49             Useage is like grep where you pass it a block and a list, returns a list of three arrayrefs. The
50             intent here though is to break that list in to three parts using cmp-style returns (-1/0/1). All
51             values that cause your codeblock to return -1 are in the first arrayref, 0 in the next, and
52             everything else falls in the last arrayref.
53              
54             B Currently the last arrayref is a catch all for anything that does not exactly match
55             -1/0. If you write your own cusom block that returns any value other then -1/0/1 then it will
56             end up here. This was done as I want to keep the expectation that all items from the input list
57             will be found some where in the output.
58              
59             my ($x,$y,$z) = trisect { $_ < 5 ? -1
60             : $_ > 5 ? 1
61             : 'foo'
62             } 1..10;
63             # $x == [1..4]
64             # $y == []
65             # $z == [5..10]
66              
67             =cut
68              
69             sub trisect (&@) {
70 2     2 1 5566 require Scalar::Util;
71 2         3 my $cmp = shift;
72              
73 2         3 my @lt;
74             my @eq;
75 0         0 my @gt;
76 2         4 foreach $_ (@_) {
77 20         58 my $val = &$cmp;
78 20 100       76 if (Scalar::Util::looks_like_number($val) ) {
79 19 100       33 if ($val == -1) {
    100          
80 8         9 push @lt, $_;
81             }
82             elsif ($val == 0) {
83 1         3 push @eq, $_;
84             }
85             else {
86 10         15 push @gt, $_;
87             }
88             }
89             else {
90 1         3 push @gt, $_;
91             }
92             }
93              
94 2         8 return (\@lt,\@eq,\@gt);
95             }
96              
97              
98              
99              
100             1;