Dave's Free Press

Technology: Sort-MultipleFields-1.01

 

Older stuff

Sort::MultipleFields - Conveniently sort on multiple fields


NAME

Sort::MultipleFields - Conveniently sort on multiple fields


SYNOPSIS

    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''.


DESCRIPTION

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.


EXPORTS

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.


SUBROUTINES

mfsort

    @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

mfsortmaker

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.


BUGS, LIMITATIONS and FEEDBACK

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.


SEE ALSO

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


AUTHOR, COPYRIGHT and LICENCE

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

This software is free-as-in-speech software, and may be used, distributed, and modified under the terms of either the GNU General Public Licence version 2 or the Artistic Licence. It's up to you which one you use. The full text of the licences can be found in the files GPL2.txt and ARTISTIC.txt, respectively.


CONSPIRACY

This module is also free-as-in-mason software.