David Cantrell > Sort-MultipleFields > Sort::MultipleFields



Annotate this POD


New  1
Open  0
View/Report Bugs
Module Version: 1.0   Source  


Sort::MultipleFields - Conveniently sort on multiple fields


    use Sort::MultipleFields qw(mfsort);

    my $library = mfsort {
        author => 'ascending',
        title  => 'ascending'
    } (
            author => 'Hoyle, Fred',
            title  => 'Black Cloud, The'
            author => 'Clarke, Arthur C',
            title  => 'Rendezvous with Rama'
            author => 'Clarke, Arthur C',
            title  => 'Islands In The Sky'

after which $library would be a reference to a list of three hashrefs, which would be (in order) the data for "Islands In The Sky", "Rendezvous with Rama", and "The Black Cloud".


This provides a simple way of sorting structured data with multiple fields. For instance, you might want to sort a list of books first by author and within each author sort by title.


The subroutines may be exported if you wish, but are not exported by default.

Default-export is bad and wrong and people who do it should be spanked.



    @sorted = mfsort { SORT SPEC } @unsorted;

Takes a sort specification and a list (or list-ref) of references to hashes. It returns either a list or a list-ref, depending on context.

The sort specification is a block structured thus:

        field1 => 'ascending',
        field2 => 'descending',
        field3 => sub {
            lc($_[0]) cmp lc($_[1]) # case-insensitive ascending

Yes, it looks like a hash. But it's not, it's a block that returns a list, and order matters.

The spec is a list of pairs, each consisting of a field to sort on, and how to sort it. How to sort is simply a function that, when given a pair of pieces of data, will return -1, 0 or 1 depending on whether the first argument is "less than", equal to, or "greater than" the second argument. Sounds familiar, doesn't it. As short-cuts for the most common sorts, the following case-insensitive strings will work:

ascending, or asc

Sort ASCIIbetically, ascending (ie $a cmp $b)

descending, or desc

Sort ASCIIbetically, descending (ie $b cmp $a)

numascending, or numasc

Sort numerically, ascending (ie $a <= $b>)

numdescending, or numdesc

Sort numerically, descending (ie $b <= $a>)

Really old versions of perl might require that you instead pass the sort spec as an anonymous subroutine.

    mfsort sub { ... }, @list


This takes a sort spec subroutine reference like mfsort but returns a reference to a subroutine that you can use with the built-in sort function.

    my $sorter = mfsortmaker(sub {
        author => 'asc',
        title  => 'asc'
    @sorted = sort $sorter @unsorted;

Note that you need to store the generated subroutine in a variable before using it, otherwise the parser gets confused.

Using this function to generate functions for sort to use should be considered to be experimental, as it can make some versions of perl segfault. It appears to be reliable if you do this:

    my $sorter = mfsortmaker(...);
    @sorted = sort { $sorter->($a, $b) } @unsorted;

and that's what the mfsort function does internally.


If you find undocumented bugs please report them either using http://rt.cpan.org/ or by email. Ideally, I would like to receive sample data and a test file, which fails with the latest version of the module but will pass when I fix the bug.

For some unknown reason, passing sort a particularly complex subroutine generated using mfsortmaker can sometimes make perl 5.8.8 (and possibly earlier versions) segfault. I *think* I've worked around it, and at least it doesn't happen for me any more, but YMMV. It was something of a Heisenbug so the current fix doesn't fill me with confidence.


Sort::Fields for sorting data consisting of strings with fixed-length fields in them.


Copyright 2008 David Cantrell <david@cantrell.org.uk>




syntax highlighting: