I am trying to sort a multi dimensional array, and have one value always at the end of the array. The array should be sorted by ‘unitText’ (dont care how unitID is sorted), but always have “Last” as the last value in the array. I’ve almost got it, but not quite there.
<?php
function cmp($a, $b)
{
/*
$a = preg_replace('@^(Last) @', '', $a);
$b = preg_replace('@^(Last) @', '', $b);
return strcasecmp($a, $b);
*/
if(strtolower(substr($a['unitText'],0,4))=="last") return strnatcmp($a['unitText'],9999);
else if(strtolower(substr($b['unitText'],0,4))=="last") return strnatcmp(9999,$b['unitText']);
else return strnatcmp($a, $b);
//return strnatcmp($a['unitText'], $b['unitText']);
//return end($a) > end($b);
}
$unit = array(
array("unitID"=>80, "unitText"=>"Q701"),
array("unitID"=>30, "unitText"=>"H568"),
array("unitID"=>25, "unitText"=>"Last"),
array("unitID"=>40, "unitText"=>"Z255"),
array("unitID"=>20, "unitText"=>"A459")
);
echo "<pre>";
print_r($unit);
echo "</pre>";
echo "<hr/>";
//uksort($unit['unitText'], "cmp");
//array_multisort($unit['unitText'], SORT_DESC, $unit['unitID'], SORT_ASC, $unit);
usort($unit, 'cmp');
echo "<pre>";
print_r($unit);
echo "</pre>";
?>
Should end up with:
Array
(
[0] => Array
(
[unitID] => 20
[unitText] => A459
)
[1] => Array
(
[unitID] => 30
[unitText] => H568
)
[2] => Array
(
[unitID] => 80
[unitText] => Q701
)
[3] => Array
(
[unitID] => 40
[unitText] => Z255
)
[4] => Array
(
[unitID] => 25
[unitText] => Last
)
)
What am I doing wrong?
Your problem is with this line:
Remember that
$aand$bare both arrays, butstrnatcmp()compares strings. When this function is called, your two arrays will be implicitly cast to strings, which will both have the value ofArray, so they will return as equal and will not be sorted.You should be comparing the
unitTextvalue:The fact that you didn’t see this tells me that you don’t have your
error_reportinglevel set high enough in development, since that implicit cast issues anE_NOTICEwhen it occurs. In development, you should always haveerror_reporting(E_ALL | E_STRICT);set (either at the entry point for your code, or in yourphp.ini, etc.) so that any little issues get immediately flagged for you to fix.Also, there is no reason why you should be calling
strnatcmp()at all when one of the values is ‘Last’, because you already know that the value should be last. Just return1or-1(depending on which contains ‘Last’) and be done with it.Finally, you don’t need all the
elseconditions in the code. Since all paths issue areturn, you can assume that anything that comes after anifblock is only executed if the comparison fails:In the above, the second
ifonly executes if we didn’t find ‘Last’ within$a, since the function would have already ended if it had. Similarly, the finalreturnstatement (with thestrnatcmp()call) only executes if neither of the aboveifconditions passed, because either one of them would have returned a value and ended the function.It’s a little thing, but nesting a bunch of unneeded
ifandelseblocks makes the code less readable.