Costruzione di una o tabella “incrociata” “pivot” di un array in php
-
23-08-2019 - |
Domanda
Ho un array di oggetti definiti analogamente al di sotto:
$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;
Se io scorrere e scaricare l'oggetto $scores
in una tabella, che sarà simile a questo:
Round_Name Player Score ---------------------------- Round 1 Bob 10 Round 2 Bob 7 Round 1 Jack 6 Round 2 Jack 12
Quello che voglio, però, è qualcosa di simile:
Player Round 1 Round 2 Total ------------------------------- Bob 10 7 17 Jack 6 12 18
Non ho intenzione di sapere in anticipo quanti giri o giocatori ci saranno e diciamo che non posso cambiare il modo in cui gli oggetti sono costruiti.
Qual è il modo più efficace per fare questo in php?
Soluzione
Se si può supporre che:
- l'ordine dei punteggi nella matrice è sempre in ordine in base al nome del giocatore e poi per il numero rotondo
- il numero di giri è lo stesso per ogni giocatore
Quindi, quello che possiamo fare è il punteggio di stampa di ogni giocatore, come ci siamo trasferiti attraverso l'array, mentre il calcolo del totale nel processo, ma il ripristino, se vediamo un nuovo giocatore:
$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;
}
Esempio di output:
Player Round 0 Round 1 Total
Bob 10 7 17
Jack 6 12 18
Questo dovrebbe essere abbastanza efficace perché va solo attraverso l'array una volta.
Altri suggerimenti
Per quanto posso dire, gli array di PHP sono implementati come tabelle hash (in modo occhiata / aggiornamento dovrebbe essere abbastanza efficiente) Sarà tempo di efficienza anche essere un problema, in ogni caso?
vorrei solo farlo nel modo "semplice":
$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";
}
(so che gli array non sono adeguatamente inizializzati, ma si ottiene l'idea)