Every once in a while you find your self in need of a generic sorting function that orders in a very specific, and non-machine understandable way. Like sorting items from ‘one’ to ‘four’. Instead of building a small subset of those kind of sort operations into the language PHP has usort family (short for user-defined sort). In the background this sort still works as a quicksort, but the developer is tasked with making a function that does the comparison between different elements of the array. It’s up to him to define whether a value is smaller, equal or bigger than another.
So, keeping the ‘one’ to ‘four’ example, I present you with a very simple custom sort function.
function customCompare($a, $b) { // We flip the array to get the positional indices $order = array_flip(array('one', 'two', 'three', 'four')); // Sanity check, $a and $b must exist in the order array foreach(array($a, $b) as $arg) { if(!array_key_exists($arg, $order)) trigger_error("`$arg' is not a sortable key"); } // The positions in the order array dictate if $a is bigger // than $b, as such we can simply subtract the integers // from the flipper order array to get an integer value // which is smaller, equal or bigger than 0 depending on // $a and $b's relative position in the array. return $order[$a] - $order[$b]; } // An example array to be sorted $example = array( 'four' => 4, 'one' => 1, 'three' => 3, 'two' => 2); // Do the actual sort uksort($example, 'customCompare'); // Dump results print_r($example);
The dumped array will look like this
Array
(
[one] => 1
[two] => 2
[three] => 3
[four] => 4
)
If you, like me, like closures and are running PHP 5.3, we can make the compare function a lot nicer and easier to maintain.
function createSorter($order) { $order = array_flip($order); return function($a, $b) use ($order) { // Sanity check, again foreach(array($a, $b) as $arg) { if(!array_key_exists($arg, $order)) trigger_error("`$arg' is not a sortable key"); } return $order[$a] - $order[$b]; } } // Sort array $array in the 'one' to 'four' order. uksort($array, createSorter( array('one', 'two', 'three', 'four')));