我正在开发一个足球比赛管理系统,我遇到了问题。我必须向用户展示基于不同属性的轮队排名。我现在正在考虑以下顺序:
通过不同的数据库查询检索构建此模型的数据,我现在用来保存它们的结构就是这样的对象数组:
对于大多数排序属性,我可以使用php array_multisort 功能并完成工作,但问题在于团队对抗。举个例子,假设我有这种情况:
在这种情况下,我认为C队应该保持在A以上,因为C击败A而我应该检查目标差异(顺序中的下一个属性)以确定B位置与B和C相比。 我正在尝试开发一种算法,能够使用任何属性配置对此问题进行排序,但到目前为止还没有运气。有人有什么建议吗?非常感谢,如果我不清楚,请原谅我
答案 0 :(得分:1)
你所谓的团队对抗实际上是一个新的表格,用于仅使用它们之间的游戏与相同点数搭配的团队。如果你有3个或更多的团队以点数捆绑,这个问题会变成一个特别令人讨厌的情况,在这种情况下,你不能使用一对一的比较(这是所有排序算法所做的)对位置表进行排序,因为你需要了解其他团队绑定以创建您的子表。 您需要创建一个给出匹配列表的函数,并且团队列表会为这些团队生成您的位置表,并通过仅关注点进行排序。在返回位置表之前,检查是否存在具有相同点的组,并将表的该部分替换为所有匹配的递归调用的结果,但仅替换绑定的组。确保在整个表绑定时停止递归,否则你会得到无限循环,在这种情况下应用全局目标差异,得分和按字母顺序排列。
PD:我之前尝试过解决这个问题,并在意识到我正在处理不可比较的集合之后放弃了。如果您实际实现它,我将非常乐意查看代码。答案 1 :(得分:0)
@ilcavero完全正确。
我实现了类似的东西。我的代码假设“对抗”排序解决关系无法运行,除非(a)所有玩家互相玩过并且(b)一名玩家赢得所有比赛或一名玩家输掉并列队伍之间的所有比赛。
这个if语句避免了这样的问题:
爱丽丝需要领先鲍勃,而不是卡尔。 Bob需要领先于Carl并落后于Alice,但Alice需要落后于Carl。它打破了。它还避免惩罚或奖励某人他们没有参加的比赛。
代码 解决看起来像这样的联系:
我们可以首先删除击败其他玩家的Alice,并将她置于并列球队之上:
由于鲍勃输给了卡尔,我们可以将他从领带中移开并将他放在领带下面的位置(此时此刻只是卡尔)。解决:
我在排序时将排名保持在这样的结构中($ 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]);
}