I\'ve found a few answers to sorting by value, but not key.
What I\'d like to do is a reverse sort, so with:
$nametocode[\'reallylongname\']=\'12
The code below sorts the PHP hash array by string length of the key, then by the case-sensitive key itself, both in ascending order, using a lambda function:
uksort($yourArray, function ($a, $b) {
return (strlen($a) == strlen($b) ? strcmp($a, $b) : strlen($a) - strlen($b));
});
This code does the same in reverse order:
uksort($yourArray, function ($b, $a) {
return (strlen($a) == strlen($b) ? strcmp($a, $b) : strlen($a) - strlen($b));
});
Take a look on uksort.
Based on @thetaiko answer, with a simpler callback :
function sortByLengthReverse($a, $b){
return strlen($b) - strlen($a);
}
uksort($nametocode, "sortByLengthReverse");
One limitation while sorting the keys on the basis of length is that: equal length keys are not re-ordered. Say we need to order the keys by length in descending
order.
$arr = array(
"foo 0" => "apple",
"foo 1" => "ball",
"foo 2 foo 0 foo 0" => "cat",
"foo 2 foo 0 foo 1 foo 0" => "dog",
"foo 2 foo 0 foo 1 foo 1" => "elephant",
"foo 2 foo 1 foo 0" => "fish",
"foo 2 foo 1 foo 1" => "giraffe"
);
debug($arr, "before sort");
$arrBad = $arr;
sortKeysDescBAD($arrBad);
debug($arrBad, "after BAD sort");
sortKeysDescGOOD($arr);
debug($arr, "after GOOD sort 2");
function sortKeysDescBAD(&$arrNew) {
$arrKeysLength = array_map('strlen', array_keys($arrNew));
array_multisort($arrKeysLength, SORT_DESC, $arrNew);
//return max($arrKeysLength);
}
function sortKeysDescGOOD(&$arrNew) {
uksort($arrNew, function($a, $b) {
$lenA = strlen($a); $lenB = strlen($b);
if($lenA == $lenB) {
// If equal length, sort again by descending
$arrOrig = array($a, $b);
$arrSort = $arrOrig;
rsort($arrSort);
if($arrOrig[0] !== $arrSort[0]) return 1;
} else {
// If not equal length, simple
return $lenB - $lenA;
}
});
}
function debug($arr, $title = "") {
if($title !== "") echo "<br/><strong>{$title}</strong><br/>";
echo "<pre>"; print_r($arr); echo "</pre><hr/>";
}
Output will be:
before sort
Array
(
[foo 0] => apple
[foo 1] => ball
[foo 2 foo 0 foo 0] => cat
[foo 2 foo 0 foo 1 foo 0] => dog
[foo 2 foo 0 foo 1 foo 1] => elephant
[foo 2 foo 1 foo 0] => fish
[foo 2 foo 1 foo 1] => giraffe
)
after BAD sort
Array
(
[foo 2 foo 0 foo 1 foo 0] => dog
[foo 2 foo 0 foo 1 foo 1] => elephant
[foo 2 foo 0 foo 0] => cat
[foo 2 foo 1 foo 0] => fish
[foo 2 foo 1 foo 1] => giraffe
[foo 0] => apple
[foo 1] => ball
)
after GOOD sort
Array
(
[foo 2 foo 0 foo 1 foo 1] => elephant
[foo 2 foo 0 foo 1 foo 0] => dog
[foo 2 foo 1 foo 1] => giraffe
[foo 2 foo 1 foo 0] => fish
[foo 2 foo 0 foo 0] => cat
[foo 1] => ball
[foo 0] => apple
)
Notice the order of elephant
and dog
for example (or others) in two sorting methods. The second method looks better. There may be easier ways to solve this but hope this helps someone...
To absolutely use uksort you can do like this:
$nametocode['reallylongname']='12';
$nametocode['name']='17';
$nametocode['shortname']='10';
$nametocode['mediumname']='11';
uksort($nametocode, function($a, $b) {
return strlen($a) - strlen($b);
});
array_reverse($nametocode, true);
Output:
Array
(
[reallylongname] => 12
[mediumname] => 11
[shortname] => 10
[name] => 17
)
I have tested this code.
Another solution using array_multisort:
$keys = array_map('strlen', array_keys($arr));
array_multisort($keys, SORT_DESC, $arr);
Here $keys
is an array of the lengths of the keys of $arr
. That array is sorted in descending order and then used to sort the values of $arr
using array_multisort
.