1379

How can I sort this array by the value of the "order" key?

Even though the values are currently sequential, they will not always be.

Array
(
    [0] => Array
        (
            [hashtag] => a7e87329b5eab8578f4f1098a152d6f4
            [title] => Flower
            [order] => 3
        )

    [1] => Array
        (
            [hashtag] => b24ce0cd392a5b0b8dedc66c25213594
            [title] => Free
            [order] => 2
        )

    [2] => Array
        (
            [hashtag] => e7d31fc0602fb2ede144d18cdffd816b
            [title] => Ready
            [order] => 1
        )
)
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
stef
  • 26,771
  • 31
  • 105
  • 143
  • 1
    Cross-Linked: [Reference: all basic ways to sort arrays and data in PHP](http://stackoverflow.com/q/17364127/367456) – hakre Oct 30 '13 at 09:48
  • the quickest way is to use the isomorphic [sort-array](https://github.com/75lb/sort-array) module which works natively in both browser and node, supporting any type of input, computed fields and custom sort orders. – Lloyd Oct 21 '19 at 20:26

17 Answers17

2104

Try a usort. If you are still on PHP 5.2 or earlier, you'll have to define a sorting function first:

function sortByOrder($a, $b) {
    if ($a['order'] > $b['order']) {
        return 1;
    } elseif ($a['order'] < $b['order']) {
        return -1;
    }
    return 0;
}

usort($myArray, 'sortByOrder');

Starting in PHP 5.3, you can use an anonymous function:

usort($myArray, function($a, $b) {
    if ($a['order'] > $b['order']) {
        return 1;
    } elseif ($a['order'] < $b['order']) {
        return -1;
    }
    return 0;
});

With PHP 7 you can use the spaceship operator:

usort($myArray, function($a, $b) {
    return $a['order'] <=> $b['order'];
});

Finally, in PHP 7.4 you can clean up a bit with an arrow function:

usort($myArray, fn($a, $b) => $a['order'] <=> $b['order']);

To extend this to multi-dimensional sorting, reference the second/third sorting elements if the first is zero - best explained below. You can also use this for sorting on sub-elements.

usort($myArray, function($a, $b) {
    $retval = $a['order'] <=> $b['order'];
    if ($retval == 0) {
        $retval = $a['suborder'] <=> $b['suborder'];
        if ($retval == 0) {
            $retval = $a['details']['subsuborder'] <=> $b['details']['subsuborder'];
        }
    }
    return $retval;
});

If you need to retain key associations, use uasort() - see comparison of array sorting functions in the manual.

Dharman
  • 30,962
  • 25
  • 85
  • 135
Christian Studer
  • 24,947
  • 6
  • 46
  • 71
  • If you need fallback/tiebreaker sorting without any function calls to prepare values, then declare an array of rules on both sides of a single spaceship operator. [1](https://stackoverflow.com/a/61119066/2943403) [2](https://stackoverflow.com/a/44309755/2943403) If subsequent sorting rules incorporate functional overhead, then use the `?:` (ternary operator) between subsequent spaceship operator comparisons. [3](https://stackoverflow.com/a/62276444/2943403) so that no extra functions are unnecessarily called. – mickmackusa Dec 07 '20 at 22:17
  • Last example can be simplified with `?:` operator : `usort($myArray, fn($a, $b) => $a['order'] <=> $b['order'] ?: $a['suborder'] <=> $b['suborder'] ?: $a['subsuborder'] <=> $b['subsuborder'] );` – fred727 Jun 03 '23 at 14:48
304
function aasort (&$array, $key) {
    $sorter = array();
    $ret = array();
    reset($array);
    foreach ($array as $ii => $va) {
        $sorter[$ii] = $va[$key];
    }
    asort($sorter);
    foreach ($sorter as $ii => $va) {
        $ret[$ii] = $array[$ii];
    }
    $array = $ret;
}

aasort($your_array, "order");
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
o0'.
  • 11,739
  • 19
  • 60
  • 87
296

I use this function:

function array_sort_by_column(&$arr, $col, $dir = SORT_ASC) {
    $sort_col = array();
    foreach ($arr as $key => $row) {
        $sort_col[$key] = $row[$col];
    }

    array_multisort($sort_col, $dir, $arr);
}

array_sort_by_column($array, 'order');

Edit This answer is at least ten years old, and there are likely better solutions now, but I am adding some extra info as requested in a couple of comments.

It works because array_multisort() can sort multiple arrays. Example input:

Array
(
    [0] => Array
        (
            [hashtag] => a7e87329b5eab8578f4f1098a152d6f4
            [title] => Flower
            [order] => 3
        )

    [1] => Array
        (
            [hashtag] => b24ce0cd392a5b0b8dedc66c25213594
            [title] => Free
            [order] => 2
        )

First $sort_col is made which is an two dimensional array with the values being what we want to sort by and the keys matching the input array. For example for this input, choosing key $sort_col "order" we get:

Array
(
    [0] => 3,
    [1] => 2
)

array_multisort() then sorts that array (resulting in key order 1, 0) but this is only the two dimensional array. So the original input array is also passed as the $rest argument. As the keys match it will be sorted so its keys are also in the same order, giving the desired result.

Note:

  • it is passed by reference so that the supplied array is modified in place.
  • array_multisort() can sort multiple additional array like this, not just one
Tom Haigh
  • 57,217
  • 21
  • 114
  • 142
  • An explanation would be in order. E.g., what is the idea/gist? What are the tradeoffs compared to other solutions? What are the performance characteristics, both theoretical and actual examples performance measurements? For instance, is this solution dog slow or not? – Peter Mortensen Jun 06 '21 at 22:36
131

To achieve this we can use "array_multisort" method which 'Sorts multiple or multi-dimensional arrays'. It's method parameters are

  • $keys - an array being sorted
  • SORT_ASC - sort order (ascending)
  • sort flags (compare items normally(don't change types) or numerically or as strings)
  • $new - then rest of the arrays. Only elements corresponding to equivalent elements in previous
    arrays are compared.

'sort flags' is SORT_REGULAR by default and it is omitted.

$new = [
    [
        'hashtag' => 'a7e87329b5eab8578f4f1098a152d6f4',
        'title' => 'Flower',
        'order' => 3,
    ],
    [
        'hashtag' => 'b24ce0cd392a5b0b8dedc66c25213594',
        'title' => 'Free',
        'order' => 2,
    ],
    [
        'hashtag' => 'e7d31fc0602fb2ede144d18cdffd816b',
        'title' => 'Ready',
        'order' => 1,
    ],
];
$keys = array_column($new, 'order');
array_multisort($keys, SORT_ASC, $new);
var_dump($new);

Result:

Array
(
    [0] => Array
        (
            [hashtag] => e7d31fc0602fb2ede144d18cdffd816b
            [title] => Ready
            [order] => 1
        )
    [1] => Array
        (
            [hashtag] => b24ce0cd392a5b0b8dedc66c25213594
            [title] => Free
            [order] => 2
        )
    [2] => Array
        (
            [hashtag] => a7e87329b5eab8578f4f1098a152d6f4
            [title] => Flower
            [order] => 3
        )
)
Peter VARGA
  • 4,780
  • 3
  • 39
  • 75
ajuchacko91
  • 1,559
  • 1
  • 10
  • 4
  • 1
    While I liked learning about the spaceship operator, this seems the most understandable and straightforward answer with useful options like SORT_DESC and multiple options for sort_flags (https://www.php.net/manual/en/function.array-multisort.php). – Eric P May 23 '22 at 23:38
  • This is preferred because it can be expressed as a one-liner. – DanimalReks Aug 19 '22 at 14:48
86

I usually use usort, and pass my own comparison function. In this case, it is very simple:

function compareOrder($a, $b)
{
  return $a['order'] - $b['order'];
}
usort($array, 'compareOrder');

In PHP 7 using the spaceship operator:

usort($array, function($a, $b) {
    return $a['order'] <=> $b['order'];
});
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jan Fabry
  • 7,221
  • 2
  • 36
  • 41
26

To sort the array by the value of the "title" key, use:

uasort($myArray, function($a, $b) {
    return strcmp($a['title'], $b['title']);
});

strcmp compare the strings.

uasort() maintains the array keys as they were defined.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
B.K
  • 847
  • 10
  • 6
  • This answer is ignoring the OP's requirements. The question asks how to sort on the `order` column. Regardless, the spaceship operator (demonstrated in the accepted answer) performs this same comparison without making iterated function calls. – mickmackusa Dec 07 '20 at 22:01
23

Use array_multisort(), array_map()

array_multisort(array_map(function($element) {
      return $element['order'];
  }, $array), SORT_ASC, $array);

print_r($array);

DEMO

Shahbaz A.
  • 4,047
  • 4
  • 34
  • 55
Ghanshyam Nakiya
  • 1,602
  • 17
  • 24
19
$sort = array();
$array_lowercase = array_map('strtolower', $array_to_be_sorted);
array_multisort($array_lowercase, SORT_ASC, SORT_STRING, $alphabetically_ordered_array);

This takes care of both upper and lower case alphabets.

Udo Held
  • 12,314
  • 11
  • 67
  • 93
Nitrodbz
  • 1,276
  • 1
  • 15
  • 25
9

As the accepted answer states you can use:

usort($myArray, function($a, $b) {
    return $a['order'] <=> $b['order'];
});

If you need sort by more than one column, then you would do the following:

usort($myArray, function($a, $b) {
    return [$a['column1'],$a['column2']] <=> [$b['column1'],$b['column2']];
});

This can be extended to any number of columns in your data. This relies on the fact you can directly compare arrays in PHP. In the above example the array would be sorted first by column1 and then by column2. But you can sort by the columns in any order e.g.:

usort($myArray, function($a, $b) {
    return [$a['column2'],$a['column1']] <=> [$b['column2'],$b['column1']];
});

If you need to sort one column ascending and another descending, then swap the descending column to the other side of the operator <=>:

usort($myArray, function($a, $b) {
    return [$a['column1'],$b['column2']] <=> [$b['column1'],$a['column2']];
});
Guillermo Phillips
  • 2,176
  • 1
  • 23
  • 40
  • An earlier [demonstration of multi-column sorting](https://stackoverflow.com/a/54647220/2943403) of which there will be many on Stack Overflow in the last 14 years of content generation. And [another](https://stackoverflow.com/a/44309755/2943403) – mickmackusa Jun 21 '22 at 05:45
  • And [this one](https://stackoverflow.com/a/54647220/2943403). Hmm the more I re-read the question and this answer, it seems that this answer should have been posted on a different page because it is duplicating the advice in the accepted answer and then extends the question scope. It would have been better to find a page that doesn't yet demonstrate how to sort on multiple columns. – mickmackusa Jun 21 '22 at 05:51
  • I guess I would be agnostic about where my answer belongs. You're right that I answered more than the question asked. People will find either this question or the other ones, so there is more likelihood that they will come across our answers and this (easy) way of sorting. We just need upvotes! – Guillermo Phillips Jun 22 '22 at 08:40
  • @Ben which part of this answer do you think does not work until PHP7.4? The spaceship operator was available back in PHP7. Proof: https://3v4l.org/sdhdo – mickmackusa Jan 03 '23 at 07:03
  • This only works with PHP 7.0 and above. (This corrects my prior comment, which incorrectly stated 7.4 instead of 7.0.) @mickmackusa – Ben Shoval Jan 04 '23 at 16:53
7

The most flexible approach would be using this method:

Arr::sortByKeys(array $array, $keys, bool $assoc = true): array

Here's why:

  • You can sort by any key (also nested like 'key1.key2.key3' or ['k1', 'k2', 'k3'])

  • It works both on associative and not associative arrays ($assoc flag)

  • It doesn't use references - it returns a new sorted array

In your case it would be as simple as:

$sortedArray = Arr::sortByKeys($array, 'order');

This method is a part of this library.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Minwork
  • 838
  • 8
  • 9
7

The working "arrow function" syntax with PHP 7.4 and above:

uasort($yourArray, fn($a, $b) => $a['order'] <=> $b['order']);

pretty print

echo '<pre>';
print_r($yourArray);
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
dılo sürücü
  • 3,821
  • 1
  • 26
  • 28
  • 1
    How difficult would it be to reverse the order? Can the fn be changed or does it call for an `array_reverse`? – Shivanand Sharma Jan 29 '22 at 07:17
  • Tiny detail it is called the [spaceship operator](https://www.php.net/manual/en/migration70.new-features.php). – theking2 May 10 '22 at 06:01
  • ```uasort($yourArray, fn($a, $b) => -1*($a['order'] <=> $b['order'])); ``` reverse... – dılo sürücü May 18 '22 at 08:51
  • Do not multiply by `-1`. That will give your code a smell. Simply reverse the order of `$a` and `$b`. `$b['order'] <=> $a['order']` [This answer](https://stackoverflow.com/a/54647220/2943403) explains. – mickmackusa Jan 03 '23 at 07:05
3

If anyone needs sort according to a key, the best is to use the below:

usort($array, build_sorter('order'));

function build_sorter($key) {
   return function ($a, $b) use ($key) {
      return strnatcmp($a[$key], $b[$key]);
   };
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Zahid
  • 39
  • 3
2

This solution is for usort() with an easy-to-remember notation for multidimensional sorting. The spaceship operator <=> is used, which is available from PHP 7.

usort($in,function($a,$b){
  return $a['first']   <=> $b['first']  //first asc
      ?: $a['second']  <=> $b['second'] //second asc
      ?: $b['third']   <=> $a['third']  //third desc (a b swapped!)
      //etc
  ;
});

Examples:

$in = [
  ['firstname' => 'Anton', 'surname' => 'Gruber', 'birthdate' => '03.08.1967', 'rank' => 3],
  ['firstname' => 'Anna', 'surname' => 'Egger', 'birthdate' => '04.01.1960', 'rank' => 1],
  ['firstname' => 'Paul', 'surname' => 'Mueller', 'birthdate' => '15.10.1971', 'rank' => 2],
  ['firstname' => 'Marie', 'surname' => 'Schmidt ', 'birthdate' => '24.12.1963', 'rank' => 2],
  ['firstname' => 'Emma', 'surname' => 'Mueller', 'birthdate' => '23.11.1969', 'rank' => 2],
];

First task: Order By rank asc, surname asc

usort($in,function($a,$b){
  return $a['rank']      <=> $b['rank']     //first asc
      ?: $a['surname']   <=> $b['surname']  //second asc
  ;
});

Second task: Order By rank desc, surname asc, firstmame asc

usort($in,function($a,$b){
  return $b['rank']      <=> $a['rank']       //first desc
      ?: $a['surname']   <=> $b['surname']    //second asc
      ?: $a['firstname'] <=> $b['firstname']  //third asc
  ;
});

Third task: Order By rank desc, birthdate asc

The date cannot be sorted in this notation. It is converted with strtotime.

usort($in,function($a,$b){
  return $b['rank']      <=> $a['rank']       //first desc
      ?: strtotime($a['birthdate']) <=> strtotime($b['birthdate'])    //second asc
  ;
});
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
jspit
  • 7,276
  • 1
  • 9
  • 17
  • This question is only sorting on one column. Your answer caters more to this page: https://stackoverflow.com/q/3232965/2943403 and https://stackoverflow.com/q/7127764/2943403 – mickmackusa Aug 13 '21 at 09:10
2

You could use usort and a user-defined sort function with a callback function:

usort($new, fn($a, $b) => $a['order'] - $b['order']);

TRICK: you could use a > b or a - b or a <=> b for sorting in an ascending order. For a descending order just the swap position of a and b.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
XMehdi01
  • 5,538
  • 2
  • 10
  • 34
  • 1
    Do all these options result in a stable sort? – Peter Mortensen Jun 06 '21 at 22:46
  • If using arrow functions (PHP7.4 or higher), there isn't any excuse for avoiding the spaceship operator (PHP7 or higher). Subtraction gives the code a smell in my opinion and isn't ideal for non-numeric data. – mickmackusa Jan 03 '23 at 07:42
0
 example  with class:
 
 class user
 {
     private $key;

     public function __construct(string $key)
     {
         $this->key = $key;
     }

     public function __invoke($a, $b)
     {
         return $a[$this->key] <=> $b[$this->key];
     }
 }

 $user = [
     ['id' => 1, 'name' => 'Oliver', 'id_card' => 4444],
     ['id' => 3, 'name' => 'Jack', 'id_card' => 5555],
     ['id' => 2, 'name' => 'Harry', 'id_card' => 6666]
 ];

 // sort user by id
 usort($user, new user('id'));
 var_dump($user);
0

Another function based on the same logic :

function array_multisort(&$a, array $column_names) {
    usort($a, function($a, $b) use($column_names) {
        foreach ($column_names as $column_name => $order) {
            $result = ($a[$column_name] <=> $b[$column_name]) * ($order === SORT_DESC ? -1 : 1);
            if ($result) return $result;
        }
        return 0;
    });
}


$data[] = array('volume' => 67, 'edition' => 2);
$data[] = array('volume' => 86, 'edition' => 1);
$data[] = array('volume' => 85, 'edition' => 6);
$data[] = array('volume' => 98, 'edition' => 2);
$data[] = array('volume' => 86, 'edition' => 6);
$data[] = array('volume' => 67, 'edition' => 7);


var_dump($data);
array_multisort($data, ['volume' => SORT_ASC, 'edition' => SORT_DESC]);
var_dump($data);
fred727
  • 2,644
  • 1
  • 20
  • 16
-2

Let's face it: PHP does not have a simple out-of-the box function to properly handle every array sort scenario.

This routine is intuitive, which means faster debugging and maintenance:

// Automatic population of the array
$tempArray = array();
$annotations = array();
// ... some code
// SQL $sql retrieves result array $result
// $row[0] is the ID, but is populated out of order (comes from
// multiple selects populating various dimensions for the same DATE
// for example
while($row = mysql_fetch_array($result)) {
    $needle = $row[0];
    arrayIndexes($needle);  // Create a parallel array with IDs only
    $annotations[$needle]['someDimension'] = $row[1]; // Whatever
}
asort($tempArray);
foreach ($tempArray as $arrayKey) {
    $dataInOrder = $annotations[$arrayKey]['someDimension'];
    // .... more code
}

function arrayIndexes ($needle) {
    global $tempArray;
    if (!in_array($needle, $tempArray)) {
        array_push($tempArray, $needle);
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
tony gil
  • 9,424
  • 6
  • 76
  • 100
  • 6
    "Let's face it: php does NOT have a simple out of the box function to properly handle every array sort scenario." That's exactly what usort/ksort/asort are designed for ^^' – benftwc Apr 23 '18 at 13:19
  • 6
    Actually PHP **has** [a lot of sorting functions](http://php.net/manual/en/array.sorting.php) that can be used to handle every array sort scenario. – axiac May 29 '18 at 16:31
  • 1
    With regard to debugging and maintenance, the use of `global` is a huge red flag and is [generally discouraged](https://stackoverflow.com/a/1558073/1144627). Why is `mysql_fetch_array` being demonstrated for this question instead of the OP's source array, and that there is no explanation of what your code is doing and what one can expect the outcome to be? Overall this is a very complex approach at achieving the desired end result. – Will B. May 01 '19 at 15:50
  • 1
    @tonygil I am not able to determine what your expected results are from your answer and the the OP's dataset. It may be obvious to you, but I do not know how your answer answers the OP's question. However, you can [pass by-reference](https://www.php.net/manual/en/language.references.pass.php) instead of using `global` see: https://3v4l.org/FEeFC This produces an explicitly defined variable, rather than one that can be changed and accessed globally. – Will B. May 02 '19 at 21:07
  • 1
    This answer is too much of a departure from the original question. How can researchers compare this solution against the other answers and arrive at a favorite if this snippet doesn't resemble the question's sample data? – mickmackusa Dec 27 '21 at 07:24