Skip to content

Instantly share code, notes, and snippets.

@pjdietz
Last active June 13, 2018 11:52
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pjdietz/5292681 to your computer and use it in GitHub Desktop.
Save pjdietz/5292681 to your computer and use it in GitHub Desktop.
Construct a PHP comparison function for use in usort() given an array of comparion functions.
<?php
/**
* Given an ordered array of comparison functions, return one function that
* starts with the first and uses the subsequent functions in order in the
* event of equal items.
*
* @param $sortFnArr
* @param int $index
* @return callable
* @throws \Exception
*/
function makeComplexSortFunction($sortFnArr, $index = 0)
{
if (isset($sortFnArr[$index])) {
$fn1 = $sortFnArr[$index];
} else {
throw new Exception('First argument must be an array conatining at least one callable');
}
$fn2 = null;
if (isset($sortFnArr[$index + 1])) {
$fn2 = makeComplexSortFunction($sortFnArr, $index + 1);
}
return makeChainedSortFunction($fn1, $fn2);
}
/**
* Given two comparison functions, return a comparison function that uses
* the first unless it evaluates as equal, then uses the second.
*
* @param $fn1
* @param $fn2
* @return callable
*/
function makeChainedSortFunction($fn1, $fn2)
{
if (!is_callable($fn2)) {
return $fn1;
}
return function ($a, $b) use ($fn1, $fn2) {
$comp = $fn1($a, $b);
if ($comp !== 0) {
return $comp;
}
return $fn2($a, $b);
};
}
<?php
// Here's some data.
$data = array(
array(
'firstName' => 'George',
'nickname' => 'Geroge Sr.',
'age' => 62,
'favoriteColor' => 'orange'
),
array(
'firstName' => 'George',
'nickname' => 'GOB',
'age' => 42,
'favoriteColor' => 'blue'
),
array(
'firstName' => 'George',
'nickname' => 'George Michael',
'age' => 16,
'favoriteColor' => 'blue'
),
array(
'firstName' => 'Buster',
'nickname' => 'Buster',
'age' => 32,
'favoriteColor' => 'violet'
)
);
// Arrange some sort functions (defined below) in a partiular order in an array.
// Pass that array to makeComplexSortFunction() to build the complex sort function.
// Use this complex function with usort() to sort the data.
$sortArrays = array('compareFirstName', 'compareAge', 'compareColor');
$complexFn = makeComplexSortFunction($sortArrays);
usort($data, $complexFn);
print "By firstName, age, favoriteColor: \n";
foreach ($data as $bluth) {
print $bluth['nickname'] . "\n";
}
// By firstName, age, favoriteColor:
// Buster
// George Michael
// GOB
// Geroge Sr.
$sortArrays = array('compareColor', 'compareAge');
$complexFn = makeComplexSortFunction($sortArrays);
usort($data, $complexFn);
print "By favoriteColor, age: \n";
foreach ($data as $bluth) {
print $bluth['nickname'] . "\n";
}
// By favoriteColor, age:
// George Michael
// GOB
// Geroge Sr.
// Buster
// Some comare functions. These aren't particular *good* ones, as they do nothing
// as far as checking if the array keys exist, but they'll work for this demo.
function compareFirstName($a, $b) {
if ($a['firstName'] == $b['firstName']) {
return 0;
}
return $a['firstName'] > $b['firstName'] ? 1 : -1;
}
function compareAge($a, $b) {
if ($a['age'] == $b['age']) {
return 0;
}
return $a['age'] > $b['age'] ? 1 : -1;
}
function compareColor($a, $b) {
if ($a['favoriteColor'] == $b['favoriteColor']) {
return 0;
}
return $a['favoriteColor'] > $b['favoriteColor'] ? 1 : -1;
}
/**
* Given an ordered array of comparison functions, return one function that
* starts with the first and uses the subsequent functions in order in the
* event of equal items.
*
* @param $sortFnArr
* @param int $index
* @return callable
* @throws \Exception
*/
function makeComplexSortFunction($sortFnArr, $index = 0)
{
if (isset($sortFnArr[$index])) {
$fn1 = $sortFnArr[$index];
} else {
throw new Exception('First argument must be an array conatining at least one callable');
}
$fn2 = null;
if (isset($sortFnArr[$index + 1])) {
$fn2 = makeComplexSortFunction($sortFnArr, $index + 1);
}
return makeChainedSortFunction($fn1, $fn2);
}
/**
* Given two comparison functions, return a comparison function that uses
* the first unless it evaluates as equal, then uses the second.
*
* @param $fn1
* @param $fn2
* @return callable
*/
function makeChainedSortFunction($fn1, $fn2)
{
if (!is_callable($fn2)) {
return $fn1;
}
return function ($a, $b) use ($fn1, $fn2) {
$comp = $fn1($a, $b);
if ($comp !== 0) {
return $comp;
}
return $fn2($a, $b);
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment