Query Results To Display With Order Rank Number Question

Ultimately, I’d like to display two values (userName and total_score) in a table sorted by score from highest to lowest with their number of rank.

Table columns to be rank, username, total score in that order.

I will at some point need to deal with tie-breakers. I have a system of various tie-breakers that I may need to tweak the database table structure and sorting for my final array, but that’s a job for another day.

I have the following code which displays the userName and total_score in the first two columns of the table. I need to somehow get the rank into mix, but have not had any luck.


$weekstandings = Array ( [0] => Array ( [userName] => BobSmith [total_score] => 149 ) [1] => Array ( [userName] => SmpleUser [total_score] => 148 ) [2] => Array ( [userName] => JohnS [total_score] => 135 ) ) 

echo '<table id="league-members">';
echo '<tr><th>Rank</th><th>Username</th><th>Total Score</th>';
$rownum = 0;
foreach ($weekstandings as $displayname)
{
$rownum += 1;
echo '<tr class="row'.($rownum%2).'">';
foreach($displayname as $key)
{
echo '<td>'.$key.'</td>';
}
echo '</tr>';
}
echo '</table>';

print_r($displayname);

The print_r displays as:

Array ( [userName] => BobSmith [total_score] => 149 ) Array ( [userName] => SmpleUser [total_score] => 148 ) Array ( [userName] => JohnS [total_score] => 135 )

I know I need to get the rank into this array, but am not sure how to achieve this. I tried an array_push but did not have any luck with that. Any advise as to where to look would be greatly appreciated. I thank you in advance for any help.

-Craig

If you’re getting the data from a database, sort the results there with ORDER BY.

The results are sorting properly and the array is in the correct order, my issue is getting an actual number into the final table. Which I need to get that value into the array somehow.

I’m making headway with doing some foreach loops.

Thank you for the response though.

-Craig

Ah, I see!

In which case, try this.


<?php
foreach($members as $rank => $member){
  
}

Where $members is your array.

This code sorts an array in descending order of scores and displays the results with rankings including tied scores


<?php

$standings = array(
    'player_1' => 149,
    'player_2' => 151,
    'player_3' => 132,
    'player_9' => 172,
    'player_8' => 132,
    'player_4' => 163,
    'player_5' => 172,
    'player_6' => 120,
    'player_7' => 132
);

arsort($standings);

//display the sorted players according to rank
$rank = 1;
$tie_rank = 0;
$prev_score = -1;

foreach ($standings as $name => $score) {
    if ($score != $prev_score) {  //this score is not a tie
        $count = 0;
        $prev_score = $score;
        echo $rank . ' - ' . $score . ' - ' . $name . '<br />';
    } else { //this score is a tie
        $prev_score = $score;
        if ($count++ == 0) {
            $tie_rank = $rank-1;
        }
        echo $tie_rank . ' - ' . $score . ' - ' . $name . '<br />';
    }
    $rank++;
}
?>

But if your data is in a database you would sort using “order by” in your query and then loop through the returned result set instead of the array.

Thanks aidos, that’s a pretty good bit of code there. As I’ve been working this, I’ve actually gotten in kind of deep with some if statements to define the order for the tie breakers. I can’t have ties, so it should work out well. And I’m pretty close on cracking this, so I don’t really want to start all over in that direction.

I was able to use the following code to get close to what I need. The only issue I’m having now is it’s only returning the results from the last element of the array.


$weekstandings = Array ( [0] => Array ( [userName] => BobSmith [total_score] => 149 ) [1] => Array ( [userName] => SmpleUser [total_score] => 148 ) [2] => Array ( [userName] => JohnS [total_score] => 135 ) ) 

foreach ($weekstandings as $key => $val)
{
$new_array = array($key+1, $val[userName], $val[total_score]);
}
print_r($new_array);
$new_array2 = array($new_array);

Returns:

Array ( [0] => 3 [1] => JohnS [2] => 135 )

I need it to return:

Array([0] => Array ([0] => 1 [1] => BobSmith [2] => 149) [1] => Array ([0] => 2 [1] => SmpleUser [2] => 148) [2] => Array ([0] => 3 [1] => JohnS [2] => 135))

I’m going to get some sleep and see if I can attack it with a clear head in the morning. Although I’ll probably be having nightmares about multidimensional arrays and foreach loops all night!

No problem :slight_smile:

The code I posted sorts the array and displays the results, including rankings, whether there are any tied scores or not. So you should be able to use the logic in my posted code to help you get yours up and running.

Also, I’m not sure you need a multidimensional array since the rankings can be calculated (see my code) rather than be stored in the array.

If you run my code, hopefully what I have done will be clearer.

If you can’t have tied scores then you might be able to use array_unique to remove duplicate values, but I’m not sure if removing array elements is appropriate for your application.

The sleep didn’t help!

I’m still getting the same result of only returning the last element of the array. Searching around, it seems that there are some known faults with the foreach function in php. Both as values being passed as a reference and with unset()'ing the variable within the foreach loop.

I don’t know if my code is behaving like this because of one of these faults or if my foreach’s are just not formatted properly. I tried playing around with unset()'ing the various variables and calling them with a & to avoid the reference. I’ve also tried various methods of another foreach within the foreach but have not had any luck with anything.

I feel like I’m so close and am just overlooking something very clear.

ok, I’ve tinkered with my code a bit more and now I have a function that accepts an array of players and their scores and spits out a 2D array with each row in the array containing

player name, score, rank

The function handles both unique and tied scores.


<?php

function setRankings($standings) {
    $rankings = array();
    arsort($standings);
    $rank = 1;
    $tie_rank = 0;
    $prev_score = -1;

    foreach ($standings as $name => $score) {
        if ($score != $prev_score) {  //this score is not a tie
            $count = 0;
            $prev_score = $score;
            $rankings[$name] = array('score' => $score, 'rank' => $rank);
        } else { //this score is a tie
            $prev_score = $score;
            if ($count++ == 0) {
                $tie_rank = $rank - 1;
            }
            $rankings[$name] = array('score' => $score, 'rank' => $tie_rank);
        }
        $rank++;
    }
    return $rankings;
}

//===================================================
//test the above function

$scores = array(
    'player_1' => 149,
    'player_2' => 151,
    'player_3' => 132,
    'player_9' => 172,
    'player_8' => 132,
    'player_4' => 163,
    'player_5' => 172,
    'player_6' => 120,
    'player_7' => 132
);

$rankedScores = setRankings($scores);

//display the player rankings
foreach ($rankedScores as $player => $data) {
    echo $player . ' - ' . $data['score'] . ' - ' . $data['rank'] . '<br />';
}
?>

Thanks aidos. I’ll play around with that a little to get my hands around it. I may need an explanation or two.

I’m going to take one more shot at my code which is just the one step of getting the rank number into the array away from being done with that page. Plus at this point it’s almost like a quest!

I’ll summarise what I have done.

  1. I start off with an input associative array made up of player name as the key and their score as the value. The output from setRankings will be a 2D array where each row in the array will be the player name, score and ranking (3 columns per row). Think of a 2D array as an array of arrays.

  2. setRankings first sorts the input array by the array elements’ values (player scores) in descending order (using [fphp]arsort[/fphp])

  3. the rest of setRankings then loops through the sorted array in 2. ($standings) and assigns a ranking to each player’s score.

  4. as I loop through $standings the previous player’s score is compared to the current player’s score to see if the current score is a “tie” score or not.

  5. depending on whether the current palyer’s score is a tie with the previous or not I assign the appropriate ranking to the current player’s score and create a new row in the function’s output array, $rankings. The 1st column in $rankings contains the players name and the next 2 columns in $rankings contain the player’s current score and the determined ranking for that score.

  6. after looping through all the players’ scores in $standings, the output array $rankings is returned to the function calling statement.

  7. I then test the function by inputing an array and displaying the results to the screen.

Alright, I got it.

I was able to rework the foreach loops to get the ranking into the array.

I used the following code:


echo '<table id="league-members">';
echo '<tr><th>Rank</th><th>Username</th><th>Total Score</th>';
$rownum = 0;
foreach ($weekstandings as $order => $val)
{
$rank = ($order+1);
$new_array = array($rank, $val[userName], $val[total_score]);
$rownum += 1;
echo '<tr class="row'.($rownum%2).'">';
foreach($new_array as $key)
{
echo '<td>'.$key.'</td>';
}
echo '</tr>';
}
echo '</table>';

This did the trick. Got the rank number, username and total score into the table in the proper order. We can’t have ties with the system, so earlier in the page, I worked in the tie breakers to get the order set up properly.

aidos, thank you for your time and consideration with my dilemma and I hope this tread is helpful to anyone in need.

  • Craig

You’re welcome :slight_smile: