Building a crosstab or rotate table from an array in php

I have an array of objects defined as shown below:

$scores = array(); // Bob round 1 $s = new RoundScore(); $s->Round_Name = 'Round 1'; $s->Player_Name = 'Bob'; $s->Score = 10; $scores[0] = $s; // Bob round 2 $s = new RoundScore(); $s->Round_Name = 'Round 2'; $s->Player_Name = 'Bob'; $s->Score = 7; $scores[1] = $s; // Jack round 1 $s = new RoundScore(); $s->Round_Name = 'Round 1'; $s->Player_Name = 'Jack'; $s->Score = 6; $scores[2] = $s; // Jack round 2 $s = new RoundScore(); $s->Round_Name = 'Round 2'; $s->Player_Name = 'Jack'; $s->Score = 12; $scores[3] = $s; 

If I loop and unload the $scores object into a table, it will look something like this:

  Round_Name Player Score
 ----------------------------
 Round 1 Bob 10
 Round 2 Bob 7
 Round 1 Jack 6
 Round 2 Jack 12

I want, however, something like this:

  Player Round 1 Round 2 Total
 -------------------------------
 Bob 10 7 17
 Jack 6 12 18

I will not know in advance how many rounds or players will be, and let me say that I can not change the way objects are created.

What is the most efficient way to do this in php?

+4
source share
2 answers

If we can assume that:

  • the order of ratings in the array is always in order by player name and then round number
  • the number of rounds is the same for each player

Then what we can do is print each player’s score as we moved around the array, calculating the total in the process, but reloading it if we see a new player:

 $round_count = 0; $header_printed = false; $current_player = NULL; $current_total = 0; $current_output_line = ""; foreach ($scores as $score) { // Check whether we have to move to a new player if ($score->Player_Name != $current_player) { // Check whether we have anything to print before // resetting the variables if (!is_null($current_player)) { if (!$header_printed) { printf("%-10s", "Player"); for ($i = 0; $i < $round_count; $i++) { printf("%-10s", "Round $i"); } printf("%-10s\n", "Total"); $header_printed = true; } $current_output_line .= sprintf("%5d\n", $current_total); print $current_output_line; } // Reset the total and various variables for the new player $round_count = 0; $current_player = $score->Player_Name; $current_total = 0; $current_output_line = sprintf("%-10s", $score->Player_Name); } $round_count++; $current_total += $score->Score; $current_output_line .= sprintf("%5d ", $score->Score); } // The last player is not printed because we exited the loop // before the print statement, so we need a print statement here. if ($current_output_line != "") { $current_output_line .= sprintf("%5d\n", $current_total); print $current_output_line; } 

Output Example:

 Player Round 0 Round 1 Total Bob 10 7 17 Jack 6 12 18 

This should be quite efficient as it only goes through the array.

+2
source

As far as I can tell, PHP arrays are implemented as hash tables (therefore, searching / updating should be quite efficient) Anyway, will time efficiency even be a problem?

I would just do this β€œeasy” way:

 $table = array(); $round_names = array(); $total = array(); foreach ($scores as $score) { $round_names[] = $score->Round_Name; $table[$score->Player_Name][$score->Round_Name] = $score->score; $total[$score->Player_Name] += $score->score; } $round_names = array_unique($round_names); foreach ($table as $player => $rounds) { echo "$player\t"; foreach ($round_names as $round) echo "$rounds[$round]\t"; echo "$total[$player]\n"; } 

(I know that arrays are not properly initialized, but you get the idea)

+6
source

All Articles