Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

assigning 'points' to array based on position, how to deal with ties?

Tags:

php

I have an array filled with arrays with a name, then a gross amount. This array is then being assigned a "points total" based on their gross ranking. The points decreases by 2 with every rank, but my issue is how can i deal with ties? Ideally i'd see how many ties, add up the total points for those rankings, then divide it by how many are tied, but i have no clue how to really accomplish that

Here is my array usort:

function grossSort($gross, $compare) {
    if($gross['gross'] > $compare['gross'])
        return -1; // move up
    else if($gross['gross'] < $compare['gross'])
        return 1; // move down
    else
        return 0; // do nothing
}

turns my array into this:

Array
(
    [0] => Array
        (
            [instr] => lee
            [gross] => 2094
        )

    [1] => Array
        (
            [instr] => steve
            [gross] => 1334
        )

    [2] => Array
        (
            [instr] => nick
            [gross] => 0
        )

    [3] => Array
        (
            [instr] => amber
            [gross] => 0
        )

    [4] => Array
        (
            [instr] => lindsey
            [gross] => 0
        )

)

And here's what im doing to assign points now:

$maxpoints = 40;            
for($i = 0; $i < count($trainergross); $i++){
    $trainergross[$i]['points'] += $maxpoints;
    $maxpoints -=2;
}

and now my array looks like this:

Array
(
    [0] => Array
        (
            [instr] => lee
            [gross] => 2094
            [points] => 40
        )

    [1] => Array
        (
            [instr] => steve
            [gross] => 1334
            [points] => 38
        )

    [2] => Array
        (
            [instr] => nick
            [gross] => 0
            [points] => 36
        )

    [3] => Array
        (
            [instr] => amber
            [gross] => 0
            [points] => 34
        )

    [4] => Array
        (
            [instr] => lindsey
            [gross] => 0
            [points] => 32
        )

)

And here's my issue, there are 4 people "tied" but getting decreasing points, I have no clue how to address this in the current way my code is set up. Anyone have any guidance?

like image 754
robz228 Avatar asked Aug 12 '13 17:08

robz228


1 Answers

You can store the last known value as you iterate, and only decrease the points when the value changed. The array is sorted, so the equal elements will be adjacent.

/**
 * award average of points to a number of elements.
 * @param arrayref $trainergross - reference to the original array
 * @param int $award - total points to award
 * @param int $start_index - which element to start with?
 * @param int $count - how many elements should be awarded points?
 * @return void
 */
function award_points(&$trainergross, $award, $start_index, $count=1)
{
    if(!$count || $award<1) return; // if noone is waiting for the award, OR there is no award, bail out

    // $awards holds total award, and we need to
    $avgPoints = $award / $count;

    // award points to $count previous elements
    for($j = $start_index; $j < $start_index + $count; ++$j)
    {
        // in case points key was not initialized, php will issue a notice.
        if(!isset($trainergross[$j]['points'])) $trainergross[$j]['points'] = 0;

        $trainergross[$j]['points'] += $avgPoints;
    }
}

/**
 * This is increased on purpose
 * the first check will be <some number> vs null, which will result in -=2.
 * this is to eliminate additional !== null test inside the loop.
 */
$maxpoints = 42;

// This will be used to store number of consecutive elements
$count = 0;

// This will be used to store total points to award
$award = 0;

// Here we will store last gross value
$last = null;

for($i = 0; $i < count($trainergross); $i++)
{
    $maxpoints -= 2;

    // if gross has not changed, just count consecutive elements and continue
    if($last == $trainergross[$i]['gross'])
    {
        $award += $maxpoints;
        $count++;
        continue;
    }

    // store gross value
    $last = $trainergross[$i]['gross'];

    // now really distribute the points we've gathered in award by now
    award_points($trainergross, $award, $i - $count, $count);

    // reset count back to 1 (there is only 1 "consecutive" element now)
    $count = 1;

    // next element will get this award
    $award = $maxpoints;
}

// now we have to award points again
// the loop ended, but $count of elements are still awaiting points...
award_points($trainergross, $award, $i - $count, $count);
like image 53
poncha Avatar answered Sep 19 '22 14:09

poncha