PHP - sort hash array by key length

蓝咒 提交于 2020-04-09 06:44:38

问题


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';
    $nametocode['shortname']='10';
    $nametocode['mediumname']='11';

I'd like them to be in this order

  1. reallylongname
  2. mediumname
  3. shortname

mediumname shortname

Many thanks


回答1:


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.




回答2:


You can use a user defined key sort function as a callback for uksort:

function cmp($a, $b)
{
    if (strlen($a) == strlen($b))
        return 0;
    if (strlen($a) > strlen($b))
        return 1;
    return -1;
}

uksort($nametocode, "cmp");

foreach ($nametocode as $key => $value) {
    echo "$key: $value\n";
}

Quick note - to reverse the sort simply switch "1" and "-1".




回答3:


Based on @thetaiko answer, with a simpler callback :

function sortByLengthReverse($a, $b){
    return strlen($b) - strlen($a);
}

uksort($nametocode, "sortByLengthReverse");

Resources :

  • php.net - uksort()
  • php.net - Sorting arrays
  • php.net - strlen()



回答4:


Behold my powerful inline methodologies. Preserve global space for the generations to come!

uksort($data, create_function('$a,$b', 'return strlen($a) < strlen($b);'));



回答5:


I have benchmarked some of sorting algorithms since performance is important for my project - here's what I've found (averaged result ran 1000x, sorted field had cca 300 elements with key size 3-50 chars):

  • 2.01 sec ... uksort with anonymous create_function (by cojam)
  • 0.28 sec ... array_multisort (by Gumbo)
  • 2.69 sec ... uksort with non-anonymous function (by Colin Herbert) - surprise for me,
  • 0.15 sec ... simple foreach + arsort

Sometime simple foreach still wins. Using dynamic PHP features has some performance penalty, obviously.




回答6:


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...




回答7:


Take a look on uksort.




回答8:


In PHP7+ you can use uksort() with spaceship operator and anonymous function like this:

uksort($array, function($a, $b) {
    return strlen($b) <=> strlen($a);
});



回答9:


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));
});



回答10:


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.




回答11:


A simple problem requires a simple solution ;-)

arsort($nametocode, SORT_NUMERIC);
$result = array_keys($nametocode);


来源:https://stackoverflow.com/questions/3955536/php-sort-hash-array-by-key-length

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!