Search code examples
phparraysloopsforeachunset

Reduce an array of objects to the 'best 10'


I have an array of objects, which are Soccer players. The array can contain anything from zero to thousands of players. I want to reduce it to the best 10. My initial attempt was as follows :

while (count($ArrayOfPlayers) > 10) {

    $ArrayIndex = 0;
    $WorstPlayerIndex = -1;
    $WorstPlayerSkill = 9999999999;
    foreach ($ArrayOfPlayers as $Player) {
        $Skill = $Player->RatingsArray['Skill'];
        if ($Skill < $WorstPlayerSkill) {
            $WorstPlayerIndex = $ArrayIndex;
            $WorstPlayerSkill = $Skill;
        }
        $ArrayIndex += 1;
    }

    // Found the worst player in the list, so remove him.
    unset($ArrayOfPlayers[$WorstPlayerIndex]);
}

Having read through similar posts, I'm aware now that the problem is that the array isn't actually being changed, so the while loop continues forever (the computer does indeed lock).

So my attempt at correcting it is as follows, based on advice from other posts.

while (count($ArrayOfPlayers) > 10) {

        $WorstIndexPlayer = 0;
        $WorstPlayerSkill = 9999999999;
        foreach ($ArrayOfPlayers as $key => &$Player) {
            $Skill = $Player->RatingsArray['Skill'];
            if ($Skill < $WorstPlayerSkill) {
                $WorstIndexPlayer = $key;
                $WorstPlayerSkill = $Skill;
            }
        }
        // Found the worst player in the list, so remove him.
        unset($ArrayOfPlayers[$WorstIndexPlayer]);
}

As you can probably tell, I don't understand what I'm doing at this point and don't understand what the $key part is for (it's just copied from other examples). It still just hangs the PC.

How do I correct this, or is there a better way altogether to achieve this?

In response to the request for the data structure, here is a dump of just 2 players to show how they're arranged.

Array
(
[0] => Player Object
    (
        [ID] => 1
        [TeamID] => 1
        [Name] => Joseph Dorrington
        [RatingsArray] => Array
            (
                [Skill] => 51993
            )
    )

[1] => Player Object
    (
        [ID] => 2
        [TeamID] => 1
        [Name] => Oliver Tillyard
        [RatingsArray] => Array
            (
                [Skill] => 64574
            )

    )

Solution

  • Using usort, you can first sort the array by this value, and then, using array_slice, take first 10 elements:

    function cmp($a, $b){
        if ($a->RatingsArray['Skill'] == $b->RatingsArray['Skill']) {
            return 0;
        }
        return ($a->RatingsArray['Skill'] > $b->RatingsArray['Skill']) ? -1 : 1;
    }
    usort($ArrayOfPlayers, "cmp");
    $ArrayOfPlayers = array_slice($ArrayOfPlayers, 0, 10);