array_multisort() can be used to sort several arrays at once, or a multi-dimensional array by one or more dimensions. Associative (string) keys will be maintained, but numeric keys will be re-indexed. Note: If two members compare as equal, they retain their original order.
Sorting a multidimensional array by element containing date. Use the usort() function to sort the array. The usort() function is PHP builtin function that sorts a given array using user-defined comparison function. This function assigns new integral keys starting from zero to array elements.
The array_multisort() function returns a sorted array. You can assign one or more arrays. The function sorts the first array, and the other arrays follow, then, if two or more values are the same, it sorts the next array, and so on.
To PHP sort array by key, you should use ksort() (for ascending order) or krsort() (for descending order). To PHP sort array by value, you will need functions asort() and arsort() (for ascending and descending orders).
I 'd like to add my own solution here, since it offers features that other answers do not.
Specifically, advantages of this solution include:
DateTime
instance).usort
or uasort
).array_multisort
: while array_multisort
is convenient, it depends on creating a projection of all your input data before sorting. This consumes time and memory and may be simply prohibitive if your data set is large.function make_comparer() {
// Normalize criteria up front so that the comparer finds everything tidy
$criteria = func_get_args();
foreach ($criteria as $index => $criterion) {
$criteria[$index] = is_array($criterion)
? array_pad($criterion, 3, null)
: array($criterion, SORT_ASC, null);
}
return function($first, $second) use (&$criteria) {
foreach ($criteria as $criterion) {
// How will we compare this round?
list($column, $sortOrder, $projection) = $criterion;
$sortOrder = $sortOrder === SORT_DESC ? -1 : 1;
// If a projection was defined project the values now
if ($projection) {
$lhs = call_user_func($projection, $first[$column]);
$rhs = call_user_func($projection, $second[$column]);
}
else {
$lhs = $first[$column];
$rhs = $second[$column];
}
// Do the actual comparison; do not return if equal
if ($lhs < $rhs) {
return -1 * $sortOrder;
}
else if ($lhs > $rhs) {
return 1 * $sortOrder;
}
}
return 0; // tiebreakers exhausted, so $first == $second
};
}
Throughout this section I will provide links that sort this sample data set:
$data = array(
array('zz', 'name' => 'Jack', 'number' => 22, 'birthday' => '12/03/1980'),
array('xx', 'name' => 'Adam', 'number' => 16, 'birthday' => '01/12/1979'),
array('aa', 'name' => 'Paul', 'number' => 16, 'birthday' => '03/11/1987'),
array('cc', 'name' => 'Helen', 'number' => 44, 'birthday' => '24/06/1967'),
);
The function make_comparer
accepts a variable number of arguments that define the desired sort and returns a function that you are supposed to use as the argument to usort
or uasort
.
The simplest use case is to pass in the key that you 'd like to use to compare data items. For example, to sort $data
by the name
item you would do
usort($data, make_comparer('name'));
See it in action.
The key can also be a number if the items are numerically indexed arrays. For the example in the question, this would be
usort($data, make_comparer(0)); // 0 = first numerically indexed column
See it in action.
You can specify multiple sort columns by passing additional parameters to make_comparer
. For example, to sort by "number" and then by the zero-indexed column:
usort($data, make_comparer('number', 0));
See it in action.
More advanced features are available if you specify a sort column as an array instead of a simple string. This array should be numerically indexed, and must contain these items:
0 => the column name to sort on (mandatory)
1 => either SORT_ASC or SORT_DESC (optional)
2 => a projection function (optional)
Let's see how we can use these features.
To sort by name descending:
usort($data, make_comparer(['name', SORT_DESC]));
See it in action.
To sort by number descending and then by name descending:
usort($data, make_comparer(['number', SORT_DESC], ['name', SORT_DESC]));
See it in action.
In some scenarios you may need to sort by a column whose values do not lend well to sorting. The "birthday" column in the sample data set fits this description: it does not make sense to compare birthdays as strings (because e.g. "01/01/1980" comes before "10/10/1970"). In this case we want to specify how to project the actual data to a form that can be compared directly with the desired semantics.
Projections can be specified as any type of callable: as strings, arrays, or anonymous functions. A projection is assumed to accept one argument and return its projected form.
It should be noted that while projections are similar to the custom comparison functions used with usort
and family, they are simpler (you only need to convert one value to another) and take advantage of all the functionality already baked into make_comparer
.
Let's sort the example data set without a projection and see what happens:
usort($data, make_comparer('birthday'));
See it in action.
That was not the desired outcome. But we can use date_create
as a projection:
usort($data, make_comparer(['birthday', SORT_ASC, 'date_create']));
See it in action.
This is the correct order that we wanted.
There are many more things that projections can achieve. For example, a quick way to get a case-insensitive sort is to use strtolower
as a projection.
That said, I should also mention that it's better to not use projections if your data set is large: in that case it would be much faster to project all your data manually up front and then sort without using a projection, although doing so will trade increased memory usage for faster sort speed.
Finally, here is an example that uses all the features: it first sorts by number descending, then by birthday ascending:
usort($data, make_comparer(
['number', SORT_DESC],
['birthday', SORT_ASC, 'date_create']
));
See it in action.
You can use array_multisort()
Try something like this:
foreach ($mdarray as $key => $row) {
// replace 0 with the field's index/key
$dates[$key] = $row[0];
}
array_multisort($dates, SORT_DESC, $mdarray);
For PHP >= 5.5.0 just extract the column to sort by. No need for the loop:
array_multisort(array_column($mdarray, 0), SORT_DESC, $mdarray);
With usort. Here's a generic solution, that you can use for different columns:
class TableSorter {
protected $column;
function __construct($column) {
$this->column = $column;
}
function sort($table) {
usort($table, array($this, 'compare'));
return $table;
}
function compare($a, $b) {
if ($a[$this->column] == $b[$this->column]) {
return 0;
}
return ($a[$this->column] < $b[$this->column]) ? -1 : 1;
}
}
To sort by first column:
$sorter = new TableSorter(0); // sort by first column
$mdarray = $sorter->sort($mdarray);
Here's another approach using uasort() and an anonymous callback function (closure). I've used that function regularly. PHP 5.3 required – no more dependencies!
/**
* Sorting array of associative arrays - multiple row sorting using a closure.
* See also: http://the-art-of-web.com/php/sortarray/
*
* @param array $data input-array
* @param string|array $fields array-keys
* @license Public Domain
* @return array
*/
function sortArray( $data, $field ) {
$field = (array) $field;
uasort( $data, function($a, $b) use($field) {
$retval = 0;
foreach( $field as $fieldname ) {
if( $retval == 0 ) $retval = strnatcmp( $a[$fieldname], $b[$fieldname] );
}
return $retval;
} );
return $data;
}
/* example */
$data = array(
array( "firstname" => "Mary", "lastname" => "Johnson", "age" => 25 ),
array( "firstname" => "Amanda", "lastname" => "Miller", "age" => 18 ),
array( "firstname" => "James", "lastname" => "Brown", "age" => 31 ),
array( "firstname" => "Patricia", "lastname" => "Williams", "age" => 7 ),
array( "firstname" => "Michael", "lastname" => "Davis", "age" => 43 ),
array( "firstname" => "Sarah", "lastname" => "Miller", "age" => 24 ),
array( "firstname" => "Patrick", "lastname" => "Miller", "age" => 27 )
);
$data = sortArray( $data, 'age' );
$data = sortArray( $data, array( 'lastname', 'firstname' ) );
I know it's 2 years since this question was asked and answered, but here's another function that sorts a two-dimensional array. It accepts a variable number of arguments, allowing you to pass in more than one key (ie column name) to sort by. PHP 5.3 required.
function sort_multi_array ($array, $key)
{
$keys = array();
for ($i=1;$i<func_num_args();$i++) {
$keys[$i-1] = func_get_arg($i);
}
// create a custom search function to pass to usort
$func = function ($a, $b) use ($keys) {
for ($i=0;$i<count($keys);$i++) {
if ($a[$keys[$i]] != $b[$keys[$i]]) {
return ($a[$keys[$i]] < $b[$keys[$i]]) ? -1 : 1;
}
}
return 0;
};
usort($array, $func);
return $array;
}
Try it here: http://www.exorithm.com/algorithm/view/sort_multi_array
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With