2

I have a multidimensional array and I want to sort based off the 'rating'... but I also want the index to start at 1 which is what I used when manually creating these. When I use usort it rearranges the array but now they start at index 0 so I can't do a loop from 1 - 6 because 6 is undefined after sort.

It was cleaner to start my $array at 1 so $player[$i] represented that actual player number. Here's what my array looks like before sort

$player[1]['rating'] = 8
$player[2]['rating'] = 5
$player[3]['rating'] = 10

Here's my sort function:

function sortByrating($a, $b) {
    if ($a['rating'] == $b['rating']) {
        return 0;
    }
    return ($a['rating'] < $b['rating']) ? -1 : 1;
}

And I call it by

usort($player, 'sortByRating');
Chief
  • 127
  • 9
  • "Player number" meaning there's an association that should be kept? I.e. whoever has key `1` should still have key `1` after sorting, but that key may be sorted elsewhere? In that case you should be using `uasort`. – Otherwise, if the `1` is just used for outputting "1.", you should *not* bend over backwards here; arrays are zero-indexed, period, add `+ 1` for visual output when needed. – deceze May 16 '17 at 02:40
  • Probably should just use a `foreach()` loop or start your `for()` loop from 0. – Enstage May 16 '17 at 02:59

2 Answers2

3

The easiest way is to add this code after usort:

array_unshift($player,'temp');
unset($player[0]);

Full code:

function sortByrating($a, $b) {
    return $a['rating'] - $b['rating'];
}

$player[1]['rating'] = 8;
$player[2]['rating'] = 5;
$player[3]['rating'] = 10;

usort($player, 'sortByRating');

array_unshift($player,'temp');
unset($player[0]);

print_r($player);

Output:

Array
(
    [1] => Array
        (
            [rating] => 5
        )

    [2] => Array
        (
            [rating] => 8
        )

    [3] => Array
        (
            [rating] => 10
        )

)

UPDATE with posible solution:

function sortByrating($a, $b) {
    return $a['rating'] - $b['rating'];
}

$player[1]['rating'] = 8;
$player[2]['rating'] = 5;
$player[3]['rating'] = 10;

uasort($player, 'sortByRating');

foreach($player as $player_id=>$player_data) {
    $place++;
    $player[$player_id]['place'] = $place;
    $places[$place] = $player_id;
    echo "Player #{$player_id} takes Place #{$place}\n";
}

echo "\nPlayers array: ";
print_r($player);

echo "\nPlaces array: ";
print_r($places);

Ouput:

Player #2 takes Place #1
Player #1 takes Place #2
Player #3 takes Place #3

Players array: Array
(
    [2] => Array
        (
            [rating] => 5
            [place] => 1
        )

    [1] => Array
        (
            [rating] => 8
            [place] => 2
        )

    [3] => Array
        (
            [rating] => 10
            [place] => 3
        )

)

Places array: Array
(
    [1] => 2
    [2] => 1
    [3] => 3
)
Sergey Khalitov
  • 987
  • 7
  • 17
  • I tried the array_unshit and then unset and that did solve the problem. nice and easy. thanks – Chief May 16 '17 at 02:34
  • @Chief, please, don't forget to mark the best answers when you recieve answers that solves your problems. – Sergey Khalitov May 16 '17 at 02:37
  • If you're using PHP7+, you can use the [Spaceship Operator](http://php.net/manual/en/migration70.new-features.php#migration70.new-features.spaceship-op) to streamline the comparison code return statement to `return $a['rating'] <=> $b['rating'];` – fubar May 16 '17 at 02:37
  • I believe uasort works just the same without needing those 2 lines after you sort, as it keeps the indexes I believe. – Chief May 16 '17 at 02:38
  • 1
    @Chief, `uasort` will return Array(2=>5, 1=>8, 3=>10)... it just reorder positions of array rows and technicaly it will return the same array... – Sergey Khalitov May 16 '17 at 02:43
  • after I do the uasort, if I do a print_r($player); the array looks great... However if I do a for loop and echo $player[$i]['rating'] it lists all the players from the original array before sorting. Is that normal? – Chief May 16 '17 at 02:54
  • Yes, because `uasort()` does not reindex the array. If you loop over the array using `foreach()` it will work in the correct order. You can use `$player = array_combine(range(1, count($player)), $player);` to reindex the array, as in my answer. – Enstage May 16 '17 at 02:58
  • @Chief, in your question you a asked for solution to sort multidimentional array by `rating` field with growing index from `1` to `n`... but i supose that it's not what you need... am i right that you need to sort by `rating` and set the `place` parameter to each players in array?? if it so, look at update of my answer – Sergey Khalitov May 16 '17 at 05:20
1

Just simply add the following after your usort:

$player = array_combine(range(1, count($player)), $player);

uasort() can be used such that the array keeps the original keys:

uasort($player, function ($x, $y) { 
    return $x['rating'] - $y['rating']; 
});
Enstage
  • 2,106
  • 13
  • 20