【问题标题】:PHP: sort tournament round teams by multiple attributesPHP:按多个属性对锦标赛回合球队进行排序
【发布时间】:2011-04-29 08:43:25
【问题描述】:

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

  • 团队积分(3*胜场+1*平局)
  • 团队对抗(不确定这是否正确,但我的意思是相同团队之间的比赛,即如果两支球队得分相同但一支被另一支击败,获胜者将高于失败者)李>
  • 净胜球(进球-进球)
  • 进球
  • 字母顺序

构建这个模型的数据是通过不同的数据库查询来检索的,我现在用来保存它们的结构是一个对象数组,如下所示:

  • 团队 ID
  • 打过比赛
  • 赢得比赛
  • 输掉比赛
  • 平局
  • 进球
  • 进球
  • 净胜球
  • 被击败的队伍 current one = array(teamId1,teamId2...)
  • 击败当前 one= array(teamId1,teamId2...) 的球队
  • 与当前球队打成平手的球队 = 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 相比的位置。 我正在尝试开发一种算法,能够使用任何属性配置对这个问题进行排序,但到目前为止还没有运气。有人有什么建议吗?非常感谢,如果我不清楚,请原谅我

【问题讨论】:

  • 我认为的一个选择是为具有相同积分的团队创建一个优先级列表。例如,如果我让 C 队击败 A 队,我会让 C>A,而对于 C-B,我会检查对抗比赛,如果不存在,则移动到净胜球等以在 C 和 B 之间获得优先权。当我拥有所有这些时优先级我会在正确的位置重新排列起始数组移动元素。这行得通吗?

标签: php sorting object


【解决方案1】:

你所说的团队对抗实际上是一个新的表格,它只使用他们之间的比赛来计算得分相同的球队。当您有 3 支或更多支球队得分并列时,此问题会演变成一种特别令人讨厌的情况,在这种情况下,您无法使用一对一比较(这是所有排序算法所做的)对排名表进行排序,因为您需要了解其他球队绑定到创建您的子表。 您将需要创建一个函数,该函数给出一个匹配列表,一个团队列表会为这些团队生成您的位置表,按仅关心点数进行排序。在返回位置表之前,检查是否存在具有相同分数的组,并将表的该部分替换为递归调用的结果,其中包含所有匹配项,但仅包含并列的组队。确保在整个表格被捆绑时停止递归,否则您将陷入无限循环,在这种情况下应用全局目标差异、得分目标和字母顺序。

PD:我之前尝试过解决这个问题,但在意识到我正在处理不可比较的集合后放弃了。如果你真的实现了它,我会很高兴查看代码。

【讨论】:

  • 感谢您的回答,我喜欢您的建议,这可能是唯一的方法。我优先考虑其他事情,但是当我重新处理这个问题时,我会告诉你我是否能解决这个问题。
【解决方案2】:

@ilcavero 完全正确。

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

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

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

爱丽丝需要领先于鲍勃,落后于卡尔。 Bob 需要在 Carl 之前并在 Alice 之后,但 Alice 需要在 Carl 之后。它打破了。它还可以避免因某人没有参加的比赛而对其进行惩罚或奖励。

代码确实解决了如下所示的关系:

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

我们可以先移除击败其他玩家的爱丽丝,并将她置于平局之上:

  1. 爱丽丝
  2. 鲍勃和卡尔

由于鲍勃输给了卡尔,我们可以将他从平局中移除,并将他置于平局下方的位置(此时将只是卡尔)。解决:

  1. 爱丽丝
  2. 卡尔
  3. 鲍勃

我在排序时将排名保持在这样的结构中($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]);
  }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-13
    • 1970-01-01
    相关资源
    最近更新 更多