构建“交叉表” 或“枢轴” php 中数组中的表

发布于 2024-07-15 19:36:08 字数 1077 浏览 6 评论 0原文

我有一个类似于以下定义的对象数组:

$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;

如果我循环并将 $scores 对象转储到表中,它将看起来像这样:

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

然而,我想要的是这样的:

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

我不会提前知道会有多少轮或有多少玩家,只能说我无法改变对象的构造方式。

在 php 中执行此操作最有效的方法是什么?

I have an array of objects defined similarly to the 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 through and dump 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

What I want, however, is something like this:

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

I'm not going to know in advance how many rounds or players there'll be and let's just say I can't change the way the objects are constructed.

What's the most efficient way to do this in php?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

无敌元气妹 2024-07-22 19:36:08

据我所知,PHP 数组是作为哈希表实现的(因此查找/更新应该非常有效)
无论如何,时间效率会成为问题吗?

我会用“简单”的方式来做:(

$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";
}

我知道数组没有正确初始化,但你明白了)

As far as I can tell, PHP arrays are implemented as hash tables (so lookup/update should be pretty efficient)
Will time efficiency even be a problem, anyway?

I would just do it the "simple" 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 the arrays aren't properly initialized, but you get the idea)

鸩远一方 2024-07-22 19:36:08

如果我们可以假设:

  • 数组中分数的顺序始终按照玩家姓名的顺序
    然后根据轮数,
  • 每个玩家的轮数相同

然后,我们可以做的是在遍历数组时打印每个玩家的得分,同时计算过程中的总数,但如果我们看到新玩家则重置它:

$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;
}

示例输出:

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

这应该非常有效,因为它只遍历数组一次。

If we can assume that:

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

Then, what we can do is print each player's score as we moved through the array while calculating the total in the process but resetting 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;
}

Sample output:

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

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文