You could replace the sort and nsort virtual methods with your own.
The below example uses Data::Sorting which is available from CPAN.

Template usage example:

[% FOREACH person = people.sort('last_name', 'first_name', 'middle_initial') %]

or

[% FOREACH person = people.nsort('area_code', 'postal_code', 'age') %]

Caveats:

For speed reasons, sorting on 0 or 1 keys will use the original
sorting method, and sorting on 2 or more keys uses the new one.
Initial tests indicate the multi-key sort is about five times
slower than a native perl sort().

Also, please note that this new sort does not automatically
Do The Right Thing when operating on an array of blessed objects.
Sorting in the underlying Data::Sorting module only operates on
hash values.  Fixing this deficiency is left as an exercise.

##

use strict;
use Template;
use Data::Sorting ':arrays';

$Template::Stash::LIST_OPS->{'sort'} = sub {

  $^W = 0;
  my ($list, @fields) = @_;
  return $list unless @$list > 1;     # no need to sort 1 item lists

  if (@fields > 1) {

    return [
      sorted_arrayref (
        $list, -compare => 'textual', map { -sortkey => $_ } @fields
      )
    ];

  } else {

    my $field = $fields[0];

    return @fields                    # Schwartzian Transform
      ?  map  { $_->[0] }             # for case insensitivity
        sort { $a->[1] cmp $b->[1] }
        map  { [ $_, lc(ref($_) eq 'HASH'
          ? $_->{ $field } :
          UNIVERSAL::can($_, $field)
          ? $_->$field() : $_) ] }
        @$list
      :  map  { $_->[0] }
        sort { $a->[1] cmp $b->[1] }
        map  { [ $_, lc $_ ] }
         @$list;

  }

};

$Template::Stash::LIST_OPS->{'nsort'} => sub {

  my ($list, @fields) = @_;
  return $list unless @$list > 1;     # no need to sort 1 item lists

  if (@fields > 1) {

    return [
      sorted_arrayref (
        $list, -compare => 'numeric', map { -sortkey => $_ } @fields
      )
    ];

  } else {

    my $field = $fields[0];

    return @fields                      # Schwartzian Transform
      ?  map  { $_->[0] }               # for case insensitivity
        sort { $a->[1] <=> $b->[1] }
        map  { [ $_, lc(ref($_) eq 'HASH'
          ? $_->{ $field } :
          UNIVERSAL::can($_, $field)
          ? $_->$field() : $_) ] }
        @$list
      :  map  { $_->[0] }
        sort { $a->[1] <=> $b->[1] }
        map  { [ $_, lc $_ ] }
        @$list

  }

};

# process template at this point
$template->process (...);

##

Peter Guzis
Web Administrator, Sr.
ENCAD, Inc.
- A Kodak Company
email: [EMAIL PROTECTED]
www.encad.com 

-----Original Message-----
From: Brett Sanger [mailto:[EMAIL PROTECTED]
Sent: Thursday, March 04, 2004 1:44 PM
To: [EMAIL PROTECTED]
Subject: [Templates] sort by multiple criteria?


So I have an array of hashrefs, that have date-related data (frex:
Month and year)

I've been asked to sort the output in most-recent-first order.

I tried: 
[% FOREACH Report = Reports.nsort('year').nsort('month') %]
(I expected this to be backwards, but I figured I'd mess with reverse
once I was sure this worked)

This didn't quite work as expected.  I got the results I wanted with:

[% FOREACH Report = Reports.nsort('month').nsort('year').reverse %]

But I'm not sure that that's not just an artifact of my data.

The docs (Template::Manual::VMethods) don't seem to talk about
"stacking" vmethods...what is the expected order of resolution?  Does
the sort vmethod respect the previous order where there is no change
required?

TIA

-- 
SwiftOne  /  Brett Sanger
[EMAIL PROTECTED]   

_______________________________________________
templates mailing list
[EMAIL PROTECTED]
http://lists.template-toolkit.org/mailman/listinfo/templates

_______________________________________________
templates mailing list
[EMAIL PROTECTED]
http://lists.template-toolkit.org/mailman/listinfo/templates

Reply via email to