multi-sort of associative array in PHP

arrays, php, sorting

Solution

You can use array_multisort

<?php
    $arr = Array
    (        
        'banana' => 2,
        'cherry' => 1,
        'orange' => 3,
        'grapefruit' => 1,
        'apple' => 1
    );

    $values = array_values($arr);
    $keys = array_keys($arr);

    //first sort by values desc, then sort by keys asc
    array_multisort($values, SORT_DESC, $keys, SORT_ASC, $arr);

    print_r($arr);
    // output:
    /*
    Array
    (
        [orange] => 3
        [banana] => 2
        [apple] => 1
        [cherry] => 1
        [grapefruit] => 1
    )
    */

?>

It works like this:

- for each column used to sort (values and keys for you), create new 1d array with its contents

- pass those 1d arrays to array_multisort function in your sorting order (so $values first, then $keys), add sort order for each array

- the last argument has to be the array which you want to sort

(Perhaps you will find this explanation easier to understand)

Problem

Consider the following associative array ``` $arr = Array ( [banana] => 2 [cherry] => 1 [orange] => 3 [grapefruit] => 1 [apple] => 1 ) ``` I want to sort it in a way that would be similar to the PLSQL term: `A DESC, B ASC` (where A is the value and B is the key) meaning: ``` $arr = Array ( [orange] => 3 [banana] => 2 [apple] => 1 [cherry] => 1 [grapefruit] => 1 ) ``` so that orange and banana are first because of the VALUE, but then I have apple, cherry and grapefruit in alphabetical order because they have the same VALUE. What I tried: 1. to run ksort() and then asort()/rsort() hoping that the second sort will bump up orange and banana to the beginning of the array without messing up the alphabetical sort of the other 3 items. I was wrong. it does messes everything up. So I checked out: 2. sort functions and array_multisort(). But apparently it sorts several arrays at once, or a multi-dimensional array. 3. I also tried to define the following compare function: ``` function cmp($a, $b) { foreach ($a as $key1 => $val1) { foreach ($b as $key2 => $val2) { if($val1 == $val2){ return strcmp($key1,$key2); } else if ($val1 > $val2){ return 1; } else{ // $val1 < $val2 return -1; } } } } ``` and call it with usort() but it also didn't work. So my question is: is there a PHP method that implements the requested behavior? For Eugen: I tried it and it doesn't work before sorting: ``` Array ( [lamb] => 3 [rule] => 1 [children] => 1 [teacher] => 2 [eager] => 1 ) ``` and after sorting: ``` Array ( [children] => 1 [eager] => 1 [rule] => 1 [teacher] => 2 [lamb] => 3 ) ```

Original source