PHP:按多个属性对锦标赛进行排序

时间:2011-04-29 08:43:26

标签: php sorting object

我正在开发一个足球比赛管理系统,我遇到了问题。我必须向用户展示基于不同属性的轮队排名。我现在正在考虑以下顺序:

  • 球队积分(3 *赢比赛+ 1 *平局比赛)
  • 团队对抗(不确定这是否是正确的词,但我的意思是相同的球队之间的比赛,即如果两支球队有相同的分数,但是一支球队被另一支球队击败,那么获胜的球队将胜过失败者一支)
  • 净胜球(进球得分)
  • 进球得分
  • 按字母顺序排列

通过不同的数据库查询检索构建此模型的数据,我现在用来保存它们的结构就是这样的对象数组:

  • teamId
  • 参加比赛
  • 赢了比赛
  • 丢失的比赛
  • tie matches
  • 进球得分
  • 目标
  • 目标差异
  • 当前失败的球队=阵列(teamId1,teamId2 ......)
  • 击败当前一队的队伍= array(teamId1,teamId2 ......)
  • 与当前one = array(teamId1,teamId2 ...)
  • 相关联的团队

对于大多数排序属性,我可以使用php array_multisort 功能并完成工作,但问题在于团队对抗。举个例子,假设我有这种情况:

  • A队 - 3分 - 战胜D
  • B队 - 3分 - 战胜D
  • C队 - 3分 - 战胜A
  • D队 - 0分 - 对阵D

在这种情况下,我认为C队应该保持在A以上,因为C击败A而我应该检查目标差异(顺序中的下一个属性)以确定B位置与B和C相比。 我正在尝试开发一种算法,能够使用任何属性配置对此问题进行排序,但到目前为止还没有运气。有人有什么建议吗?非常感谢,如果我不清楚,请原谅我

2 个答案:

答案 0 :(得分:1)

你所谓的团队对抗实际上是一个新的表格,用于仅使用它们之间的游戏与相同点数搭配的团队。如果你有3个或更多的团队以点数捆绑,这个问题会变成一个特别令人讨厌的情况,在这种情况下,你不能使用一对一的比较(这是所有排序算法所做的)对位置表进行排序,因为你需要了解其他团队绑定以创建您的子表。 您需要创建一个给出匹配列表的函数,并且团队列表会为这些团队生成您的位置表,并通过仅关注点进行排序。在返回位置表之前,检查是否存在具有相同点的组,并将表的该部分替换为所有匹配的递归调用的结果,但仅替换绑定的组。确保在整个表绑定时停止递归,否则你会得到无限循环,在这种情况下应用全局目标差异,得分和按字母顺序排列。

PD:我之前尝试过解决这个问题,并在意识到我正在处理不可比较的集合之后放弃了。如果您实际实现它,我将非常乐意查看代码。

答案 1 :(得分:0)

@ilcavero完全正确。

我实现了类似的东西。我的代码假设“对抗”排序解决关系无法运行,除非(a)所有玩家互相玩过并且(b)一名玩家赢得所有比赛或一名玩家输掉并列队伍之间的所有比赛。

这个if语句避免了这样的问题:

  • 爱丽丝击败鲍勃
  • 鲍勃击败卡尔
  • 卡尔击败爱丽丝

爱丽丝需要领先鲍勃,而不是卡尔。 Bob需要领先于Carl并落后于Alice,但Alice需要落后于Carl。它打破了。它还避免惩罚或奖励某人他们没有参加的比赛。

代码 解决看起来像这样的联系:

  • 爱丽丝击败鲍勃
  • 爱丽丝击败了卡尔
  • 卡尔击败鲍勃

我们可以首先删除击败其他玩家的Alice,并将她置于并列球队之上:

  1. 爱丽丝
  2. Bob&卡尔
  3. 由于鲍勃输给了卡尔,我们可以将他从领带中移开并将他放在领带下面的位置(此时此刻只是卡尔)。解决:

    1. 爱丽丝
    2. 卡尔
    3. 鲍勃
    4. 我在排序时将排名保持在这样的结构中($ this-> sortedTeams):

      [
        1 => [$id => $team, $id => $team, $id = $team], // 3 teams tied for first position.
        4 => [$id => $team], // One team in 4th position.
        5 => [$id => $team, $id => $team] // 2 teams tied in 5th position.
      ]
      

      以下是我的TeamSorter类中处理头对头比较的代码:

        private function headToHead() {
          foreach ($this->findTies() as $position)
            $this->headToHeadThisPosition($position);
          ksort($this->sortedTeams);
        }
      
        private function headToHeadThisPosition($position) {
      
          // Teams that are tied.
          $teams = $this->sortedTeams[$position];
      
          // Every team must play every other team, or head to head doesn't work.
          if (!$this->tiedTeamsHaveAllPlayedEachother($teams)) return; 
      
          // If we have a winner, it assumes $position, and other(s) assume
          // $positon + 1, moving away from first place.
          if ($winner_nid = $this->tiedPositionHasWinner($teams))
            $position = $this->removeFromTie('winner', $winner_nid, $position);
      
          // If we have a loser, it assumes $position + 1 (moving away from first
          // place), other(s) stay at $position.
          if ($loser_nid = $this->tiedPositionHasLoser($teams))
            $this->removeFromTie('loser', $loser_nid, $position);
      
          // Recursively call this function if we might resolve a tie at $position
          // before going on to the next position.
          if ($this->recursionNeeded($position))
            $this->headToHeadThisPosition($position);
        }
      
        private function recursionNeeded($position) {
          $teams = $this->sortedTeams[$position];
          return
            count($this->sortedTeams[$position]) > 1
            &&
            $this->tiedTeamsHaveAllPlayedEachother($this->sortedTeams[$position])
            &&
            $this->tiedPositionHasWinner($this->sortedTeams[$position]);
        }