aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorTom Ryder <tom@sanctum.geek.nz>2017-10-06 11:09:24 +1300
committerTom Ryder <tom@sanctum.geek.nz>2017-10-06 11:36:02 +1300
commit7fa252fe32a34065852e73aebc00272833f5537a (patch)
treef302efa68ea8df12a67ff555cf096946a75fd22d /lib
parentBump version number (diff)
downloadList-Breakdown-7fa252fe32a34065852e73aebc00272833f5537a.tar.gz
List-Breakdown-7fa252fe32a34065852e73aebc00272833f5537a.zip
Add numeric ranges checking
Diffstat (limited to 'lib')
-rw-r--r--lib/List/Breakdown.pm74
1 files changed, 70 insertions, 4 deletions
diff --git a/lib/List/Breakdown.pm b/lib/List/Breakdown.pm
index 8feafac..766098f 100644
--- a/lib/List/Breakdown.pm
+++ b/lib/List/Breakdown.pm
@@ -30,6 +30,16 @@ my %types = (
return { breakdown( $spec, @_ ) };
},
+ # If it's an array, we're doing numeric bounds checking [a,b)
+ ARRAY => sub {
+ my $bounds = shift;
+ @{$bounds} == 2
+ or croak 'ARRAY ref for bounds needs two items';
+ my $l = defined $bounds->[0] ? $bounds->[0] : '-Inf';
+ my $u = defined $bounds->[1] ? $bounds->[1] : 'Inf';
+ return [ grep { $_ >= $l and $_ < $u } @_ ];
+ },
+
# If it's a subroutine, return a arrayref of all elements for which it
# returns true
CODE => sub {
@@ -52,7 +62,7 @@ sub breakdown {
# Check the spec is a hashref
ref $spec eq 'HASH'
- or croak 'HASH reference expected for first argument';
+ or croak 'HASH ref expected for first argument';
# Start building a results hash
my %results;
@@ -60,7 +70,7 @@ sub breakdown {
# Check that the value for this key is a reference
my $ref = ref $spec->{$key}
- or croak "Reference expected for '$key'";
+ or croak "Ref expected for '$key'";
# Check it's a reference we understand
exists $types{$ref}
@@ -83,6 +93,7 @@ __END__
=for stopwords
sublists Unhandled tradename licensable MERCHANTABILITY hashrefs CPAN AnnoCPAN
+syntaxes
=head1 NAME
@@ -142,8 +153,24 @@ This puts the following structure in C<%filtered>:
Given a hash reference structure and a list of items, apply each of the
subroutines or regular expressions given as values of the hash reference,
returning a new hash in the same structure with the tests replaced with the
-items for which the subroutine returns true, in the same way as C<grep>, or (as
-a shortcut) for which the regular expression matched.
+items for which the subroutine returns true, in the same way as C<grep>.
+
+There are two shortcut syntaxes:
+
+=over 4
+
+=item *
+
+If a value in the C<spec> structure is an C<ARRAY> reference with two items, it
+will be interpreted as defining bounds C<[lower,upper)> for matched values.
+`undef` can be used to denote negative or positive infinity.
+
+=item *
+
+If it's a C<Regexp> reference, it will be interpreted as a pattern to match
+against all of the items, and will return the items that match.
+
+=back
=head1 EXAMPLES
@@ -274,6 +301,45 @@ C<%results>:
Note the extra level of hash referencing beneath the C<problem> key.
+=head2 Grouping numbers by size
+
+Suppose you have a list of stray numbers from your volcanic activity reporting
+system, some of which might be merely worrisome and some an emergency, and they
+need to be filtered to know where to send them:
+
+ my @numbers = ( 1, 32, 3718.4, 0x56, 0777, 3.14, -5, 1.2e5 );
+
+You could filter them into buckets like this, using the interval syntax; an
+array reference with exactly two elements; lower bound (inclusive) first, upper
+bound (exclusive) second:
+
+ my $filters = {
+ negative => [ undef, 0 ],
+ positive => {
+ small => [ 0, 10 ],
+ medium => [ 10, 100 ],
+ large => [ 100, undef ],
+ },
+ };
+
+Applying the bucket structure like so:
+
+ my %filtered = breakdown $filters, @numbers;
+
+The result set would look like this:
+
+ my %expected = (
+ negative => [ -5 ]
+ positive => {
+ small => [ 1, 3.14 ],
+ medium => [ 32, 86 ],
+ large => [ 3_718.4, 511, 120_000 ]
+ },
+ );
+
+Notice that you can express infinity or negative infinity as C<undef>. Note
+also this is a numeric comparison only.
+
=head1 AUTHOR
Tom Ryder C<< <tom@sanctum.geek.nz> >>