Categories

Posts in this category

Sat, 08 May 2010

List.classify


Permanent link

Yesterday I implement a nice Perl 6 built-in called classify.

Just like map it takes a closure and a list (or can be called as a method on a list). Unlike map it doesn't just return the values from the closure calls, but instead it constructs Pair objects from them, and groups them by equal keys. Here's one example:

say <red brown blue yellow black>.classify({ $_.substr(0, 1)}).perl;
# output:
# ("y" => ["yellow"], "b" => ["brown", "blue", "black"], "r" => ["red"])

This takes a list of color names, and groups them by their first letter. It returns a list of pairs, of which the key is always the first character (returned by the closure), the value is an array of the input values that have this first character.

Of course you can assign the result to a hash, and index by key you're interested in:

my %h = <red brown blue yellow black>.classify({ $_.substr(0, 1)});
say %h<b>.join(', ');
# output:
# brown, blue, black

So far I haven't come up with a real-world use case for classify, but I strongly suspect I'll run across one soon, and I kinda like the function.

Have you written any code lately where such a built-in would have been beneficial?

[/perl-6] Permanent link

Comments / Trackbacks:

Trackback URL: /blog-en/perl-6/list-classify.trackback

Sam wrote


Pretty much every program I write.

I'm not kidding, there's hardly a project I have that doesn't at some point need to, yet again, iterate over an array, pushing elements onto a hash of arrays.

The only thing that would be nice is a mechanism to allow you to map at the same time, so that the item pushed onto the arrays doesn't have to be the original item.

careytilden wrote

What Sam said
I would use this constantly. I might even throw a Perl 5 workalike into my standard toolkit.

Ricardo Signes wrote

yup, definitely
This is a better version of List::MoreUtils::part, which I wrote for perl5 and find pretty useful. Classifying into a hash rather than an array would clearly be more often useful.

colomon wrote


The specific example that made me long for this function is sorting loops on a topological face. Basically, you need to separate the counterclockwise and clockwise loops, and then look for which counterclockwise loops contain which clockwise ones. Figuring out whether a loop is clockwise is relatively expensive, so being able to go through the list of loops once and split it into two is very handy.

Darren Duncan wrote


I've already written a map-like classify function that groups into hashes, sort of. See my Set::Relation Perl 5 module. The version with map is called 'classification' and the one that just groups by values is called 'group' etc.

fagzal wrote

nice thing
I had a project where we got a list of words from SQL, which we wanted to list according to their first letter. Look at this:
http://idezetek.org/authors

So the example you used is a very good one :)

Sam wrote

Set::Relation
Darren: Set::Relation looks a bit heavy-weight and overkill for just this one task, however you've just successfully pushed back one of my other projects by at least a week, because it looks like it's an ideal fit and I won't be able to resist rewriting everything. :P

Klamsi wrote


I sometimes need this feature when selecting rows from Database.
Sometimes you need a mapping with:
column_value => [row, row, ...]

Klamsi wrote


For example think of a hierarchical forum and you want to select a whole thread.

To display the tree you can use a data structure like
%posts = @rows.classify({ $_.parent_id });

Paul "LeoNerd" Evans wrote


That looks like a Perl6 version of the partition_by functional, in Perl5's List::UtilsBy. Quite like List::MoreUtils::part() except it too has the hash valued result

Vinay wrote


This is equivalent to groovy groupBy method.

Write a comment

The comments on this blog post have been disabled; the comment form below will not work.

 
Name:
URL: [http://www.example.com/] (optional)
Title: (optional)
Comments:
Save my Name and URL/Email for next time