We have the following data:
| Last name | First name |
|---|---|
| Petrova | Sveta |
| Ivanov | Oleg |
| Petrova | Anna |
| Ivanov | Ivan |
We need to sort it by last name and first name in ascending order. How can we do that in PHP? array_multisort can help us!
More info about
array_multisort: https://www.php.net/manual/en/function.array-multisort.php
$data = [
['Petrova', 'Sveta'],
['Ivanov', 'Oleg'],
['Petrova', 'Anna'],
['Ivanov', 'Ivan'],
];
$lastNames = array_column($data, 0);
$firstNames = array_column($data, 1);
// This workaround handles cases where the columns used for sorting have equal values.
// Without it, this can lead to a fatal error: Nesting level too deep - recursive dependency?
// Thanks to Yii community https://github.com/yiisoft/yii2/issues/8348
$indexes = range(1, count($data));
array_multisort(
$lastNames,
SORT_ASC,
SORT_STRING,
$firstNames,
SORT_ASC,
SORT_STRING,
$indexes,
SORT_ASC,
SORT_NUMERIC,
$data
);
Result:
| Last name | First name |
|---|---|
| Ivanov | Ivan |
| Ivanov | Oleg |
| Petrova | Anna |
| Petrova | Sveta |
This example is simple, and we haven't used descending order yet. Let's sort last names in ascending order and first names in descending order.
array_multisort(
$lastNames,
SORT_ASC,
SORT_STRING,
$firstNames,
SORT_DESC,
SORT_STRING,
$indexes,
SORT_ASC,
SORT_NUMERIC,
$data
);
Result:
| Last name | First name |
|---|---|
| Ivanov | Oleg |
| Ivanov | Ivan |
| Petrova | Sveta |
| Petrova | Anna |
By the way, we don't have to use array_multisort. Below, I'll show how to sort by multiple fields without this "magic" function (thanks to the Doctrine community).
$data = [
['Petrova', 'Sveta'],
['Ivanov', 'Oleg'],
['Petrova', 'Anna'],
['Ivanov', 'Ivan'],
];
$orderings = [
'lastName' => SORT_ASC,
'firstName' => SORT_DESC,
];
$orderFn = null;
foreach (array_reverse($orderings) as $field => $ordering) {
$orderFn = function (array $a, array $b) use ($orderFn, $field, $ordering): int {
switch ($field) {
case 'lastName':
$column = 0;
break;
case 'firstName':
$column = 1;
break;
default:
return 0;
}
if ($a[$column] === $b[$column]) {
if ($orderFn !== null) {
return $orderFn($a, $b);
} else {
return 0;
}
}
return ($a[$column] <=> $b[$column]) * ($ordering === SORT_ASC ? 1 : -1);
};
}
uasort($data, $orderFn);
Result:
| Last name | First name |
|---|---|
| Ivanov | Oleg |
| Ivanov | Ivan |
| Petrova | Sveta |
| Petrova | Anna |