How to have a stable sort in PHP with arsort()?

Construct a new array whose elements are the original array's keys, values, and also position:

$temp = array();
$i = 0;
foreach ($array as $key => $value) {
  $temp[] = array($i, $key, $value);
  $i++;
}

Then sort using a user-defined order that takes the original position into account:

uasort($temp, function($a, $b) {
 return $a[2] == $b[2] ? ($a[0] - $b[0]) : ($a[2] < $b[2] ? 1 : -1);
});

Finally, convert it back to the original associative array:

$array = array();
foreach ($temp as $val) {
  $array[$val[1]] = $val[2];
}

This is because the sort family of functions are not stable. If you need the sort to be stable then you either have to implement it yourself, or iterate over the sorted result and "correct" the positions of the elements using array_splice.


For reference, I've put a set of stable sort variants of builtin PHP functions on Github: https://github.com/vanderlee/PHP-stable-sort-functions, based on @Barmar's solution and a few other tricks.


Simple solution with array_multisort.

$assoc = [
    70 => 1,
    82 => 5,
    61 => 3,
    55 => 1,
    34 => 2,
    53 => 2,
    21 => 4,
    13 => 5,
];

$keys = array_keys($assoc);
array_multisort($assoc, SORT_DESC, range(1, count($assoc)), $keys);
$assoc = array_combine($keys, $assoc);

print_r($assoc);

It is kinda a big workaround, but it does work:

$a = array(70 => 1 ,82 => 5  ,61 => 3 ,55 => 1 ,34 => 2 ,53 => 2 ,21 => 4 ,13 => 5);
$b = max($a);
$c = min($a);
$d = 0;
$sorted_list = array();
while($b >= $c){
    foreach($a as $key => $value){
        if($value == $b){
            $sorted_list[$key] = $value;
        }
    }
    $b--;
}

vardump output:

array(8) { [82]=> string(1) "5" [13]=> string(1) "5" [21]=> string(1) "4" [61]=> string(1) "3" [34]=> string(1) "2" [53]=> string(1) "2" [70]=> string(1) "1" [55]=> string(1) "1" }