The Sorter class is made for sorting records where each record is an associative array. For example, suppose $files is an array of the following form :
$files[] = array( 'name' => 'fred.txt', 'ext' => 'txt', 'size' => 1234 ); $files[] = array( 'name' => 'jane.jpg', 'ext' => 'jpg', 'size' => 412 ); $files[] = array( 'name' => 'readme.txt', 'ext' => 'txt', 'size' => 592 );
You can sort by extension type and size as follows:
$sorter = new Sorter("ext,-size:n"); // sort by extension (alphabetic) and descending size
$sorter->sort($files);
Basically it takes a comma separated list of field names (e.g. "region,city,area"), each of which can optionally be preceded by a “+” (default) or “-” to say whether it is an ascending or descending sort and suffixed with a type letter (e.g “:n”) to say whether the sort is alphabetic (“s” and default), numeric (“n”) or by date (“d”). The date has to be in a format PHP recognises, but simple timestamps are numeric.
I think this should also work for arrays of numerically indexed arrays, so that "3,-2:d" sorts by column 3 and then column 2 as a date descending, but I’ve not tested this.
the code
class Sorter {
var $keys;
function Sorter($keyspec) {
$this->keys = $this->parseKeys($keyspec);
}
function sort( &$arr ) {
return usort( $arr, array($this,'compare') );
}
function parseKeys($keyspec) {
$keyspecs = explode(",",$keyspec);
$keys = array();
foreach ( $keyspecs as $onespec ) {
if ( $onespec{0} == '-' ) {<
$onespec = substr($onespec,1);
$dir = '-';
} else if ( $onespec{0} == '+' ) {
$onespec = substr($onespec,1);
$dir = '+';
} else {
$dir = '+';
}
$parts = explode(':',$onespec);
if ( $parts[0] ) {
switch ( $parts[1] ) {
case 'i': case 'n':
$type = 'n'; break; // number
case 'd':
$type = 'd'; break; // date
case 's': default:
$type = 's'; break; // string
}
$keys[] = array( $parts[0], $dir, $type );
}
}
return $keys;
}
function compare( $obj1, $obj2 ) {
foreach( $this->keys as $key ) {
list( $name, $dir, $type ) = $key;
$fld1 = $obj1[$name]; $fld2 = $obj2[$name];<
switch ( $type ) {
case 'n':
$cmp = $fld1 - $fld2;
break;
case 'd':
$time1 = strtotime($fld1);
$time2 = strtotime($fld2);
if ( $time1 === false || $time1 === -1 ||
$time2 === false || $time2 === -1 ) {
// false PHP 5.1, -1 older PHP
$cmp = 0; // badly formed dates
} else {
$cmp = $time1 - $time2;
}
case 's': default:
$cmp = strcmp($fld1,$fld2);
break;
}
if ( $cmp == 0 ) continue;
if ( $dir == '-' ) $cmp = - $cmp;
return $cmp;
}
return 0;
}
}