Skip Menu |

This queue is for tickets about the List-Categorize CPAN distribution.

Report information
The Basics
Id: 80655
Status: rejected
Priority: 0/
Queue: List-Categorize

People
Owner: Nobody in particular
Requestors: DAMI [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: Wishlist
Broken in: (no value)
Fixed in: (no value)



Subject: support for multilevel categories
Hi Bill, List::Categorize is great, but sometimes I need multi-level categories. So here is a proposal for adding this functionality. Best regards, Laurent Dami =========================================== 3207f1f6674b27eb73d4b09f81a7dda7956b4f4f lib/List/Categorize.pm | 43 ++++++++++++++++++++++++----------------- -- t/categorize.t | 29 ++++++++++++++++++++++++++--- 2 files changed, 50 insertions(+), 22 deletions(-) diff --git a/lib/List/Categorize.pm b/lib/List/Categorize.pm index fd4fdc4..e08a370 100644 --- a/lib/List/Categorize.pm +++ b/lib/List/Categorize.pm @@ -66,18 +66,21 @@ sub categorize (&@) # Execute the categorizer subroutine to determine the category # for this element. # - my $category = $coderef->(); + my @categories = $coderef->(); - # If a category was returned, use it as a key in the %sublists - # hash, and add the current element to the list referenced by - # that key. + # If categories were returned, use them as a sequence of keys + # in the %sublists hash, and add the current element to the list + # referenced by the last key. # - # If the categorizer didn't return a value (or returned undef), + # If the categorizer didn't return a list (or returned undef), # then leave this element out of %sublists entirely. # - if (defined $category) + my $sublist = \%sublists; + while (@categories && defined $categories[0]) { - push @{ $sublists{ $category } }, $_; + my $categ = shift @categories; + if (@categories) { $sublist = $sublist->{$categ} ||= {}; } + else { push @{$sublist->{$categ}}, $_; } } } @@ -111,16 +114,17 @@ This documentation describes List::Categorize version 0.01. # Transform the element before placing it in the hash. $_ = ucfirst $_; - # Use the first letter of the element as the category. - substr($_, 0, 1); + # Use the first letter of the element as the category, + # then the first 2 letters as a second-level category + substr($_, 0, 1), substr($_, 0, 2); - } qw( apple banana antelope bear canteloupe coyote ); + } qw( apple banana antelope bear canteloupe coyote ananas ); # %capitalized now contains # ( - # A => [ 'Apple', 'Antelope' ], - # B => [ 'Banana', 'Bear' ], - # C => [ 'Canteloupe', 'Coyote' ] + # A => { An => ['Antelope', 'Ananas'], Ap => ['Apple'], }, + # B => { Ba => ['Banana'], Be => ['Bear'], }, + # C => { Ca => ['Canteloupe'], Co => ['Coyote'] }, # ) =head1 DESCRIPTION @@ -139,12 +143,13 @@ Nothing by default. my %hash = categorize { $_ > 10 ? 'Big' : 'Little' } @list; C<categorize> creates a hash by running BLOCK for each element in LIST. -The block returns a hash key (the "category") for the current -element. (If it returns C<undef> for a list element, that element is -not placed in the resulting hash.) +The block returns a list of hash keys (the "categories") for the current +element. (If it returns and empty list or a list starting with C<undef>, +the corresponding element is not placed in the resulting hash.) -The resulting hash contains a key for each category, and each key refers to a -list of the elements that correspond to that category. +The resulting hash contains a key for each category or subcategory. +At the bottom leve, each key refers to a +list of the elements that correspond to that sequence of categories. Within the block, $_ refers to the current list element. Elements can be modified before they're placed in the target hash by modifying the $_ @@ -154,7 +159,7 @@ variable: # %hash now contains ( List => [ 'ONE', 'TWO', 'THREE' ] ) -NOTE: The categorizer should return a string, or C<undef>. Other values +NOTE: The categorizer should return list of strings, or C<undef>. Other values are reserved for future use, and may cause unpredictable results in the current version. diff --git a/t/categorize.t b/t/categorize.t index 857668b..1d94cb9 100644 --- a/t/categorize.t +++ b/t/categorize.t @@ -1,4 +1,4 @@ -#! perl -T +#! perl # -T # # categorize.t # @@ -8,7 +8,7 @@ use strict; use warnings; -use Test::More tests => 14; +use Test::More tests => 15; use Test::Deep; use Test::NoWarnings; @@ -65,6 +65,7 @@ test_sublist_element_transform(); test_collapsing_sublist_element_transform(); test_ignored_elements(); test_categorizer_args(); +test_multilevel_categories(); # Test::NoWarnings automatically inserts an additional test # that makes sure no warnings were emitted during testing. @@ -395,7 +396,6 @@ sub test_list_of_lists # will be a list of lists.) # my %sublists_by_length = categorize { scalar @{ $_ } } @source; - cmp_deeply(\%sublists_by_length, \%expected_by_length, 'List of lists to hash of sublists by sublist length' ); @@ -576,4 +576,27 @@ sub test_categorizer_args ); } + +sub test_multilevel_categories { + my %expected = ( + A => { An => ['Antelope', 'Ananas'], Ap => ['Apple'], }, + B => { Ba => ['Banana'], Be => ['Bear'], }, + C => { Ca => ['Canteloupe'], Co => ['Coyote'] }, + ); + + my %sublists = categorize { + $_ = ucfirst $_; + + # Use the first letter of the element as the category, + # then the first 2 letters as a second-level category + substr($_, 0, 1), substr($_, 0, 2); + + } qw( apple banana antelope bear canteloupe coyote ananas ); + + + cmp_deeply(\%sublists, \%expected, + 'Multilevel categories' + ); +} + # end categorize.t
Since I had no answer from the author, I published the proposed extension in a new distribution (List-Categorize-Multi)