Skip navigation.
Home
Your source for Perl tips, howto's, faq and tutorials
( categories: )

Sometimes you need to sort your data by multiple columns (for example, sorting a user list by age and then by last name).

If the fields you want to compare don't need any kind of processing then just put all the comparisons together (ordered by importance), separated by '||':

Example:

#-- order by age (oldest first) and the by last name
@ordered_users = sort { $b->age <=> $a->age || $a->last cmp $b->last } @users;

In case you need to do some computation to obtain the fields you want to order by, then it's better to precompute the fields first and then do the sort, otherwise your sort routine could potentially be quite inefficient.

As an example, let's say you want to order a user list by length of last name and then alphabetically by first name; to do this, you must do the following:

1. Use map to create a temporary array of arrays, the first elements of each row of the resulting array will have the values to sort by, the last element will be the row itself.

@temp = map { [ length $_[1], $_[0], $_ ] } @users;

2. Sort the resulting array using the precomputed fields

@temp = sort { $a->[0] <=> $b->[0] || $a->[1] cmp $b->[1] } temp;

3. In the previous step you obtained the ordered array, so use map to obtain the original row

@sorted_users = map { $_->[2] } @temp;

You can put all 3 steps in a single sentence like this:

@sorted_users =
     map { $_->[2] } # step 3
     sort { $a->[0] <=> $b->[0] || $a->[1] cmp $b->[1] } # step 2
     map { [ length $_[1], $_[0], $_ ] } # step 1
     @users;


With Help From this Post

And a few other sources, I was able to solve a problem at work.

Here's what I came up with:

#!/usr/bin/perl

use strict;

my @array = ( 
   "kyy1         x753y420 31082010 07:01:11", 
   "exr1         x831y444 31082010 07:43:45", 
   "eef1         x717y532 31082010 07:30:17", 
   "bab3         x789y486 31082010 08:08:56", 
   "sam1        x1017y200 31082010 07:25:18", 
   "jmd2         x789y466 31082010 07:38:22", 
   "baa3cqc      x720y440 31082010 07:26:37"
);

# Sort by first column - login name
my @sortedName = sort { (split ' ', $a)[0] cmp (split ' ', $b)[0] } @array;

# Sort by second column - SKU number
my @sortedSkno = sort { (split ' ', $a)[1] cmp (split ' ', $b)[1] } @array;

# Sort by third - date - and fourth - time - column combined!
my @sortedTime = sort { (split ' ', $a)[2].(split ' ', $a)[3] cmp (split ' ', $b)[2].(split ' ', $b)[3] } @array;

print "Array\n";
print join( "\n", @array )."\n\n";

print "Sort Name\n";
print join( "\n", @sortedName )."\n\n";

print "Sort Skno\n";
print join( "\n", @sortedSkno )."\n\n";

print "Sort Date\n";
print join( "\n", @sortedTime )."\n\n";