Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

multi-sort of associative array in PHP

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
)
like image 984
Nir Alfasi Avatar asked Jun 16 '12 08:06

Nir Alfasi


2 Answers

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)

like image 125
Zbigniew Avatar answered Nov 08 '22 11:11

Zbigniew


function polysortcmp($a, $b) {
  if ($a[1]<$b[1]) return 1;
  if ($a[1]>$b[1]) return -1;
  if ($a[0]<$b[0]) return -1;
  if ($a[0]>$b[0]) return 1;
  return 0;
}


function polysort(&$arr) {
  foreach ($arr as $k=>$v) $arr[$k]=array($k,$v);
  uasort($arr, "polysortcmp");
  foreach ($arr as $k=>$v) $arr[$k]=$v[1];
}
like image 21
Eugen Rieck Avatar answered Nov 08 '22 11:11

Eugen Rieck