preserve key order stable sort when sorting with phps uasort

preserve key order stable sort when sorting with phps uasort  using -'php,arrays,algorithm,sorting'

This question is actually inspired from another one here on SO and I wanted to expand it a bit.

Having an associative array in PHP is it possible to sort its values, but where the values are equal to preserve the original key order, using one (or more) of PHP's built in sort function?

Here is a script I used to test possible solutions (haven't found any):

header('Content-type: text/plain');
    $arr['key-'.$i] = rand(1,5)*10;
uasort($arr, function($a, $b){
    // sort condition may go here //
    // Tried: return ($a == $b)?1:($a - $b); //
    // Tried: return $a >= $b; //

Pitfall: Because the keys are ordered in the original array, please don't be tempted to suggest any sorting by key to restore to the original order. I made the example with them ordered to be easier to visually check their order in the output.

Thank you for your tested input,

asked Sep 14, 2015 by LasSander
0 votes

5 Answers

0 votes

Since PHP does not support stable sort after PHP 4.1.0, you need to write your own function.

This seems to do what you're asking:

As the manual says, "If two members compare as equal, their order in the sorted array is undefined." This means that the sort used is not "stable" and may change the order of elements that compare equal.

Sometimes you really do need a stable sort. For example, if you sort a list by one field, then sort it again by another field, but don't want to lose the ordering from the previous field. In that case it is better to use usort with a comparison function that takes both fields into account, but if you can't do that then use the function below. It is a merge sort, which is guaranteed O(n*log(n)) complexity, which means it stays reasonably fast even when you use larger lists (unlike bubblesort and insertion sort, which are O(n^2)).

Also, you may find this forum thread interesting.

answered Sep 14, 2015 by Aliza6618fyd
0 votes

array_multisort comes in handy, just use an ordered range as second array ($order is just temporary, it serves to order the equivalent items of the first array in its original order):

$a = [
  "key-0" => 5,
  "key-99" => 3,
  "key-2" => 3,
  "key-3" => 7

$order = range(1,count($a));
array_multisort($a, SORT_ASC, $order, SORT_ASC);



array(4) {

I used test data with not-ordered keys to demonstrate that it works correctly. Nonetheless, here is the output your test script:

    [key-1] => 10
    [key-4] => 10
    [key-5] => 20
    [key-8] => 20
    [key-6] => 30
    [key-9] => 30
    [key-2] => 40
    [key-0] => 50
    [key-3] => 50
    [key-7] => 50


It only works with predefined comparisons, you cannot use your own comparison function. The possible values (second parameter of array_multisort()) are:

Sorting type flags:

  • SORT_ASC - sort items ascendingly.
  • SORT_DESC - sort items descendingly.
  • SORT_REGULAR - compare items normally (don't change types)
  • SORT_NUMERIC - compare items numerically
  • SORT_STRING - compare items as strings
  • SORT_LOCALE_STRING - compare items as strings, based on the current locale. It uses the locale, which can be changed using setlocale()
  • SORT_NATURAL - compare items as strings using "natural ordering" like natsort()
  • SORT_FLAG_CASE - can be combined (bitwise OR) with SORT_STRING or SORT_NATURAL to sort strings case-insensitively
answered Sep 14, 2015 by AmeeONeillzr
0 votes

For completeness sake, you should also check out the Schwartzian transform:

// decorate step
$key = 0;
foreach ($arr as &$item) {
        $item = array($item, $key++); // add array index as secondary sort key

// sort step
asort($arr); // sort it

// undecorate step
foreach ($arr as &$item) {
    $item = $item[0]; // remove decoration from previous step

The default sort algorithm of PHP works fine with arrays, because of this:

array(1, 0) < array(2, 0); // true
array(1, 1) < array(1, 2); // true

If you want to use your own sorting criteria you can use uasort() as well:

// each parameter is an array with two elements
// [0] - the original item
// [1] - the array key
function mysort($a, $b)
    if ($a[0] != $b[0]) {
        return $a[0] < $b[0] ? -1 : 1;
    } else {
        // $a[0] == $b[0], sort on key
        return $a[1] < $b[1] ? -1 : 1; // ASC
answered Sep 14, 2015 by AdrHoeft
0 votes

For future reference, I've put a set of stable sort variants of builtin PHP functions on Github:, based on @Jack's solution and a few other tricks.

answered Sep 14, 2015 by Ade08V
0 votes

Just to complete the responses with some very specific case. If the array keys of $array are the default one, then a simple array_values(asort($array)) is sufficient (here for example in ascending order)

answered Sep 14, 2015 by GabTilly