0

I would like to display some array data in relation to a competition, each player is ranked by the number of points they have, however if a player has the same amount of points to somebody else they should both have the exact same ranking position.

For instance...

1st     Bob     500pts
2nd     Joe     350pts
3rd     Tom     250pts
3rd     Tim     250pts
5th     Jay     100pts

In this instance, as Tom & Tim have the exact same number of points they should be joint third, making the next person down 5th (rather than 4th), can anyone suggest the best way to achieve this with a simple array similar to follows

array('Bob' => 500, 'Joe' => '350', 'Tom' => '250', 'Tim' => '250', 'Jay' => '100');

Can anyone suggest the 'cleanest' solution for achieving this

Zabs
  • 13,852
  • 45
  • 173
  • 297

4 Answers4

2

This code will work for you:

$array = array('Bob' => 500, 'Joe' => '350', 'Tom' => '250', 'Tim' => '250', 'Jay' => '100');
arsort($array, SORT_NUMERIC);

$previousPoints = null;
$position = $total = 1;
foreach($array as $name=>$points) {
   if ($points != $previousPoints) {
       $position = $total;
   }

   echo $position.' '.$name.' '.$points."\n";

   $previousPoints = $points;
   $total++;
}

Online demo here.

cOle2
  • 4,725
  • 1
  • 24
  • 26
0

Try below code:

$a = array('Bob' => 500, 'Joe' => '350', 'Tom' => '250', 'Tim' => '250', 'Jay' => '100');
arsort($a);

$rank = 1;
$index = 1;
$prevUserPoints = 0;
foreach($a as $name=>$points) {
    if($points != $prevUserPoints) {
        $rank = $index;
    }
    $index++;
    echo $rank . ' ' . $name . ' ' . $points . "\n";
    $prevUserPoints = $points;
}

For displaying 1 as 1st, 2 as 2nd etc, you can use something like below:

function ordSuffix($n) {
  $str = "$n";
  $t = $n > 9 ? substr($str,-2,1) : 0;
  $u = substr($str,-1);
  if ($t==1) return $str . 'th';
    else switch ($u) {
      case 1: return $str . 'st';
      case 2: return $str . 'nd';
      case 3: return $str . 'rd';
      default: return $str . 'th';
  }
}

example: echo ordSuffix(23); This prints 23rd

Rajesh
  • 3,743
  • 1
  • 24
  • 31
0
$ar = array(
    'Bob' => 500,
    'Tim' => '250',
    'Joe' => '350',
    'Tom' => '250',
    'Jay' => '100'
);

arsort($ar, SORT_NUMERIC);

$i = 1;
$previous = 1;
$previousPosition = 1;

foreach($ar as $k => $v)
{
    if($v === $previous)
    {
        //If the value now is the same as the previous value use the previous position
        echo "Position: $previousPosition, $k : $v <br />";
    }
    else
    {
        echo "Position: $i, $k : $v <br />";
    }


    //Previous value
    $previous = $v;

    //Previous Position
    $previousPosition = $i;


    //Always increment the value
    $i++;
}
Ian
  • 3,539
  • 4
  • 27
  • 48
  • 1
    This doesn't skip to `5` for `Jay`. – cOle2 Jul 16 '14 at 16:54
  • @cOle2 I have edited and tested the code, if you need nth, nrd etc please refer to the question http://stackoverflow.com/questions/3109978/php-display-number-with-ordinal-suffix – Ian Jul 16 '14 at 17:11
0

Just a basic and alternative point of view you might want to consider.

$arr = [
    "Joe" => "350",
    "Tom" => "250",
    "Jay" => "200",   
    "Tim" => "250",
    "Bob" => "500",
    "John" => "250" ,
    "Paul" => "251.40" 
];

$rank = array();

array_walk($arr,function($v, $k) use (&$rank)
{
    if(isset($rank[$v]))
    {
        $rank[$v][$k] = $v;
        asort($rank[$v]); //alphabetical order John, Tim, Tom
    } else 
    {
        $rank[$v] = array($k => $v);
    }
});

krsort($rank);

var_dump(array_values($rank));
ilpaijin
  • 3,645
  • 2
  • 23
  • 26