marius2k12
marius2k12

Reputation: 1101

PHP Array Sort by multiple values

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

Answers (2)

Martin Ender
Martin Ender

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

Bud Damyanov
Bud Damyanov

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

Related Questions