I have the following multi-dimensional array that I want to sort.
I want to sort the innermost arrays by total_points, then tiebraker1, 2 and 3.
Example:
[
1 => [
1 => [
'userid' => 17,
'total_points' => 16,
'tiebraker1' => 1,
'tiebraker2' => 2,
'tiebraker3' => 1
],
2 => [
'userid' => 29,
'total_points' => 16,
'tiebraker1' => 1,
'tiebraker2' => 2,
'tiebraker3' => 9
]
],
2 => [
1 => [
'userid' => 26,
'total_points' => 26,
'tiebraker1' => 2,
'tiebraker2' => 2,
'tiebraker3' => 4
],
2 => [
'userid' => 17,
'total_points' => 26,
'tiebraker1' => 3,
'tiebraker2' => 2,
'tiebraker3' => 4
]
]
]
Desired result:
[
1 => [
1 => [
'userid' => 29,
'total_points' => 16,
'tiebraker1' => 1,
'tiebraker2' => 2,
'tiebraker3' => 9
],
2 => [
'userid' => 17,
'total_points' => 16,
'tiebraker1' => 1,
'tiebraker2' => 2,
'tiebraker3' => 1
]
],
2 => [
1 => [
'userid' => 17,
'total_points' => 26,
'tiebraker1' => 3,
'tiebraker2' => 2,
'tiebraker3' => 4
],
2 => [
'userid' => 26,
'total_points' => 26,
'tiebraker1' => 2,
'tiebraker2' => 2,
'tiebraker3' => 4
]
]
]
I tried using array_multisort but I can't configure it correctly.
To use array_multisort
you would need a different structure for your data. Specifically you would need to group by "score type" (or expressed mathematically, transpose the array). E.g. like this using your first example:
array(5) {
// $userid
[0] => array(2) {
[0] => 17
[1] => 29
}
// $total_points
[1] => array(2) {
[0] => 16
[1] => 16
}
// $tiebreaker1
[2] => array(4) {
[0] => 1
[1] => 1
}
// $tiebreaker2
[3] => array(2) {
[0] => 2
[1] => 2
}
// $tiebreaker3
[4] => array(2) {
[0] => 1
[1] => 9
}
}
Then you could use array_multisort()
as follows:
array_multisort($ar[1], SORT_DESC, SORT_NUMERIC,
$ar[2], SORT_DESC, SORT_NUMERIC,
$ar[3], SORT_DESC, SORT_NUMERIC,
$ar[4], SORT_DESC, SORT_NUMERIC,
$ar[0], SORT_ASC, SORT_NUMERIC);
If you cannot change the structure of the array, you could use usort()
instead and define the comparision criteria manually.
function cmp($a, $b)
{
if ($a['total_points'] != $b['total_points']) {
return ($a['total_points'] > $b['total_points']) ? -1 : 1;
} elseif ($a['tiebreaker1'] != $b['tiebreaker1']) {
return ($a['tiebreaker1'] > $b['tiebreaker1']) ? -1 : 1;
} elseif ($a['tiebreaker2'] != $b['tiebreaker2']) {
return ($a['tiebraker2'] > $b['tiebreaker2']) ? -1 : 1;
} elseif ($a['tiebreaker3'] != $b['tiebreaker3']) {
return ($a['tiebreaker3'] > $b['tiebreaker3']) ? -1 : 1;
} else {
return 0;
}
}
usort($array, "cmp");
Disclaimer: I do not claim that my implementation of cmp
is the most elegant one. But it should do the trick. :)