One frequent question we often get in #perl on Freenode concerns how to sort a list of items by some property of the items, perhaps the value of an object accessor or the result of some regexp extraction. Sometimes the answer comes in variants on a theme of
@sorted_items = sort { $a->accessor cmp $b->accessor } @items;
@sorted_items = sort { ( $a =~ m/^(\d+)/ )[0] <=> ( $b =~ m/^(\d+)/ )[0] } @items;Sometimes a mention of the Schwartzian Transform comes.
I decided to take this often-use pattern and find a nicer way to represent it. The result is the sort_by functional.
@sorted_items = sort_by { $_->accessor } @items;
@sorted_items = sort_by { ( $_ =~ m/^(\d+)/ )[0] } @items;As well as neatness of code, this also has advantage of invoking the accessor only once per item, rather than once per item pair.
An operation I've often wanted to perform is to search a list of items for the best match by some metric. For this, there is max_by and variations.
$longest = max_by { length $_ } @strings;
$closest = min_by { distance_between( $_->location, $here ) } @places;
Finally, as a replacement for the often-used pattern
@array = grep { wanted $_ } @array;We have
extract_by { not wanted $_ } @array;As noted in the documentation, this is implemented by spliceing the unwanted elements out, not by assigning a new list, so this is safe to use on lists containing weak references, or tied variables.
Very nice.
ReplyDelete