Reputation: 1101
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:
Array
(
[1] => Array
(
[1] => Array
(
[userid] => 17
[total_points] => 16
[tiebraker1] => 1
[tiebraker2] => 2
[tiebraker3] => 1
)
[2] => Array
(
[userid] => 29
[total_points] => 16
[tiebraker1] => 1
[tiebraker2] => 2
[tiebraker3] => 9
)
)
[2] => Array
(
[1] => Array
(
[userid] => 26
[total_points] => 26
[tiebraker1] => 2
[tiebraker2] => 2
[tiebraker3] => 4
)
[2] => Array
(
[userid] => 17
[total_points] => 26
[tiebraker1] => 3
[tiebraker2] => 2
[tiebraker3] => 4
)
)
)
Result:
Array
(
[1] => Array
(
[1] => Array
(
[userid] => 29
[total_points] => 16
[tiebraker1] => 1
[tiebraker2] => 2
[tiebraker3] => 9
)
[2] => Array
(
[userid] => 17
[total_points] => 16
[tiebraker1] => 1
[tiebraker2] => 2
[tiebraker3] => 1
)
)
[2] => Array
(
[1] => Array
(
[userid] => 17
[total_points] => 26
[tiebraker1] => 3
[tiebraker2] => 2
[tiebraker3] => 4
)
[2] => Array
(
[userid] => 26
[total_points] => 26
[tiebraker1] => 2
[tiebraker2] => 2
[tiebraker3] => 4
)
)
)
I tried using array_multisort but I cant configure it correctly.
Thanks in advance for your help!
Upvotes: 1
Views: 1479
Reputation: 44259
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. :)
Upvotes: 4
Reputation: 31839
From the PHP.net's documentation:
<?php
$ar = array(
array("10", 11, 100, 100, "a"),
array( 1, 2, "2", 3, 1)
);
array_multisort($ar[0], SORT_ASC, SORT_STRING,
$ar[1], SORT_NUMERIC, SORT_DESC);
var_dump($ar);
?>
In this example, after sorting, the first array will transform to "10", 100, 100, 11, "a" (it was sorted as strings in ascending order). The second will contain 1, 3, "2", 2, 1 (sorted as numbers, in descending order).
array(2) {
[0]=> array(5) {
[0]=> string(2) "10"
[1]=> int(100)
[2]=> int(100)
[3]=> int(11)
[4]=> string(1) "a"
}
[1]=> array(5) {
[0]=> int(1)
[1]=> int(3)
[2]=> string(1) "2"
[3]=> int(2)
[4]=> int(1)
}
}
Upvotes: 0