144

I have the following array structure:

[ [ "configuration_id" => 10, "id" => 1, "optionNumber" => 3, "optionActive" => 1, "lastUpdated" => "2010-03-17 15:44:12" ], [ "configuration_id" => 9, "id" => 1, "optionNumber" => 2, "optionActive" => 1, "lastUpdated" => "2010-03-17 15:44:12" ], [ "configuration_id" => 8, "id" => 1, "optionNumber" => 1, "optionActive" => 1, "lastUpdated" => "2010-03-17 15:44:12" ] ] 

What is the best way to order the array in an incremental way, based on the optionNumber?

So the results look like:

[ [ "configuration_id" => 8, "id" => 1, "optionNumber" => 1, "optionActive" => 1, "lastUpdated" => "2010-03-17 15:44:12" ], [ "configuration_id" => 9, "id" => 1, "optionNumber" => 2, "optionActive" => 1, "lastUpdated" => "2010-03-17 15:44:12" ], [ "configuration_id" => 10, "id" => 1, "optionNumber" => 3, "optionActive" => 1, "lastUpdated" => "2010-03-17 15:44:12" ] ] 

8 Answers 8

257

Use usort.

function cmp_by_optionNumber($a, $b) { return $a["optionNumber"] - $b["optionNumber"]; } ... usort($array, "cmp_by_optionNumber"); 

In PHP ≥5.3, you should use an anonymous function instead:

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

Note that both code above assume $a['optionNumber'] is an integer. Use @St. John Johnson's solution if they are strings.


In PHP ≥7.0, use the spaceship operator <=> instead of subtraction to prevent overflow/truncation problems.

usort($array, function ($a, $b) { return $a['optionNumber'] <=> $b['optionNumber']; }); 
Sign up to request clarification or add additional context in comments.

10 Comments

That doesn't really helpe me as usort requires I provide it a function to use - which is the difficult bit I can't get my head round
Well he just gave you the function to use. And you're going to have to accept that there's not always a built-in function to do what you want, you have to write it yourself. Comparison functions just require a return of 1, 0, or -1 indicating the sort order for two elements.
I looked further into usort and it is actually quite cool. I wrote a simple comparison function to the one above, however missed out the '=='. Thanks for the help guys
@KiloumapL'artélon If the result is < 0, it tells the sort function that a should appear before b. If it is > 0 then b should appear before a.
And to those who want to sort by DESC, just switch $a and $b
|
67

Use usort

 usort($array, 'sortByOption'); function sortByOption($a, $b) { return strcmp($a['optionNumber'], $b['optionNumber']); } 

3 Comments

@BenSinclair, that's because Kenny's solution is for numbers, this solution is for strings. They are both correct :-) +1 for this alternative.
For case insensitive sort use strcasecmp instead of strcmp
can we define key for second order in array means we do first sorting with optionNumber then sorting with lastUpdated. How can do this thing?
20

Using array_multisort(), array_map()

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

DEMO

4 Comments

This just works very easily. Thank you. All I had to do was change my column name and it worked.
This also preserves keys for the parent array
I know this question is a bit old by now, but I have a question: I saw that it does work, but how does it work? I've read the array_multisort docs at php.net and this still doesn't make much sense to me.
this is best answer that don't affect on buffet output by ob_start. thanks.
19

I used both solutions by KennyTM and AJ Quick and came up with a function that can help in this issue for many cases like using ASC or DESC sorting or preserving keys or if you have objects as children of array.

Here is this function (works for PHP7 and higher because of spaceship operator):

/** * @param array $array * @param string $value * @param bool $asc - ASC (true) or DESC (false) sorting * @param bool $preserveKeys * @return array * */ function sortBySubValue($array, $value, $asc = true, $preserveKeys = false) { if ($preserveKeys) { $c = []; if (is_object(reset($array))) { foreach ($array as $k => $v) { $b[$k] = strtolower($v->$value); } } else { foreach ($array as $k => $v) { $b[$k] = strtolower($v[$value]); } } $asc ? asort($b) : arsort($b); foreach ($b as $k => $v) { $c[$k] = $array[$k]; } $array = $c; } else { if (is_object(reset($array))) { usort($array, function ($a, $b) use ($value, $asc) { return $a->{$value} == $b->{$value} ? 0 : ($a->{$value} <=> $b->{$value}) * ($asc ? 1 : -1); }); } else { usort($array, function ($a, $b) use ($value, $asc) { return $a[$value] == $b[$value] ? 0 : ($a[$value] <=> $b[$value]) * ($asc ? 1 : -1); }); } } return $array; } 

Usage:

sortBySubValue($array, 'optionNumber', true, false); 

Edit

The first part can be rewritten using uasort() and the function will be shorter (works for PHP7 and higher because of spaceship operator):

/** * @param array $array * @param string $value * @param bool $asc - ASC (true) or DESC (false) sorting * @param bool $preserveKeys * @return array * */ function sortBySubValue($array, $value, $asc = true, $preserveKeys = false) { if (is_object(reset($array))) { $preserveKeys ? uasort($array, function ($a, $b) use ($value, $asc) { return $a->{$value} == $b->{$value} ? 0 : ($a->{$value} <=> $b->{$value}) * ($asc ? 1 : -1); }) : usort($array, function ($a, $b) use ($value, $asc) { return $a->{$value} == $b->{$value} ? 0 : ($a->{$value} <=> $b->{$value}) * ($asc ? 1 : -1); }); } else { $preserveKeys ? uasort($array, function ($a, $b) use ($value, $asc) { return $a[$value] == $b[$value] ? 0 : ($a[$value] <=> $b[$value]) * ($asc ? 1 : -1); }) : usort($array, function ($a, $b) use ($value, $asc) { return $a[$value] == $b[$value] ? 0 : ($a[$value] <=> $b[$value]) * ($asc ? 1 : -1); }); } return $array; } 

3 Comments

To make this work for me, I had to use > (greater than) instead of - (minus) when comparing $a and $b values since I was comparing strings. Still works though.
@James you are right. I changed the answer and added the use of spaceship operator (<=>). Now it should work just fine.
Is there a way to make this case insensitive?
4

The keys are removed when using a function like the ones above. If the keys are important, the following function would maintain it... but foreach loops are pretty inefficient.

function subval_sort($a,$subkey) { foreach($a as $k=>$v) { $b[$k] = strtolower($v[$subkey]); } asort($b); foreach($b as $key=>$val) { $c[$key] = $a[$key]; } return $c; } $array = subval_sort($array,'optionNumber'); 

Use arsort instead of asort if you want from high to low.

Code credit: http://www.firsttube.com/read/sorting-a-multi-dimensional-array-with-php/

Comments

4

The two most modern, most concise approaches are:

  1. usort() with arrow function syntax and a spaceship (3-way comparison) operator. (Demo)

    usort($array, fn($a, $b) => $a['optionNumber'] <=> $b['optionNumber'] ); 

    $a <=> $b gives ascending sorting; $b <=> $a gives descending sorting.

  2. array_multisort() with an array_column() call to isolate the value to compare. (Demo)

    array_multisort( array_column($array, 'optionNumber'), $array ); 

    It is not necessary to include the sorting direction flag because ascending is the default/implied direction when omitted.


Both approaches above require the targeted array column to exist in all rows, or the approach will fail/break/error.


The only other way to sort the rows by optionNumber is to ensure that optionNumber is the first element of each row and ensure that all rows have the same element count. Under these conditions, you could call sort(). Demo Note this is not a "stable sort" on the first column -- if there are ties to break while sorting, the next positioned set/column of values will be compared and so on. With your sample data there will be no ties to break.

Comments

3

PHP 5.3+

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

Comments

0

A one-line solution using array_multisort and array_column.

//your array $yourarray = Array ( "0" => Array ( "configuration_id" => 10, "id" => 1, "optionNumber" => 3, "optionActive" => 1, "lastUpdated" => "2010-03-17 15:44:12" ), "1" => Array ( "configuration_id" => 9, "id" => 1, "optionNumber" => 2, "optionActive" => 1, "lastUpdated" => "2010-03-17 15:44:12" ), "2" => Array ( "configuration_id" => 8, "id" => 1, "optionNumber" => 1, "optionActive" => 1, "lastUpdated" => "2010-03-17 15:44:12" ) ); //access optionNumber in the child arrays using array_column array_multisort(array_column($yourarray, 'optionNumber'), SORT_ASC, $yourarray); //print out preformatted echo "<pre>"; print_r($images); echo "</pre>"; 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.