【问题标题】:Producing a sorted football league table in Python用 Python 生成一个排序好的足球联赛表
【发布时间】:2016-09-15 11:54:46
【问题描述】:

我创建了一个程序来模拟球队之间的整个足球赛季。用户输入团队的名称和他们的技能等级。然后它使用泊松分布来比较他们的技能等级并计算两队之间的结果。每场比赛结束后,相关列表都会更新:获胜球队获得 3 分(因此,如果是第三支球队获胜,则索引 [2] 处的值增加 3)。我有一个单独的列表,包括得分、进球数、失球数、赢球数、平局数和输球数(旁注 - 有没有更有效的方法?) 我遇到的问题出现在赛季末:每支球队的数据都是按照球队最初输入的顺序输出的。这是通过“名称”列表中的团队名称与“分数”列表中的分数相同的事实来完成的。所以问题是,如果我订购“点”列表,那么它们将与他们的名字不同步。我希望这是有道理的,但这是一个季节的示例输出:

Enter number of teams in league: 4
Enter team 1 name: a
Enter team 2 name: b
Enter team 3 name: c
Enter team 4 name: d
Enter a skill: 1
Enter b skill: 3
Enter c skill: 5
Enter d skill: 8
===========================================
a's home games: 
===========================================

a 2 - 0 b 

a 0 - 2 c 

a 0 - 0 d 

===========================================
b's home games: 
===========================================

b 2 - 3 a 

b 1 - 0 c 

b 0 - 0 d 

===========================================
c's home games: 
===========================================

c 1 - 0 a 

c 1 - 0 b 

c 0 - 1 d 

===========================================
d's home games: 
===========================================

d 4 - 0 a 

d 2 - 0 b 

d 0 - 0 c 

Final table: 
a               Skill: 1     Points: 7     For: 5     Against: 9     Goal difference: -4    Wins: 2     Draws: 1     Losses: 3    
b               Skill: 3     Points: 4     For: 3     Against: 8     Goal difference: -5    Wins: 1     Draws: 1     Losses: 4    
c               Skill: 5     Points: 10    For: 4     Against: 2    Goal difference: 2     Wins: 3     Draws: 1     Losses: 2    
d               Skill: 8     Points: 12    For: 7     Against: 0    Goal difference: 7     Wins: 3     Draws: 3     Losses: 0    
[4, 7, 10, 12]

所以我现在想做的是能够按降序打印最终的排名表,而不是像现在那样按索引顺序打印。

抱歉,如果措辞不当 - 我的程序的代码可能更有用,所以这里是:

import math
import random
#Lambda value in Poisson distribution for higher rated team
lambOne = 1.148698355
#Lambda value for lower rated team
lambTwo = 0.8705505633

#Poisson distribution calculating goals scored by the home team
def homeMatch(homeRating,awayRating):
    global lambOne
    global x
    global y
    if x == y:
        raise ValueError
    else:
        lamb = lambOne**(int(homeRating)-int(awayRating))
        homeScore = 0
        z = random.random()    
        while z > 0:
            z = z - ((lamb**homeScore * math.exp(lamb * -1))/(math.factorial(homeScore)))
            homeScore += 1
        return (homeScore-1)

#Poisson distribution calculating goals scored by away team
def awayMatch(homeRating,awayRating):
    global lambTwo
    global x
    global y
    #This check is to stop a team playing itself
    if x == y:
        raise ValueError
    else:
        lamb = lambTwo**(int(homeRating)-int(awayRating))
        awayScore = 0
        z = random.random()    
        while z > 0:
            z = z - ((lamb**awayScore * math.exp(lamb * -1))/(math.factorial(awayScore)))
            awayScore += 1
        return (awayScore-1)

#Selecting number of teams in league
leagueSize = int(input("Enter number of teams in league: "))

#Initialising empty lists
teamNames = []
teamSkill = []
teamPoints = []
teamFor = []
teamAgainst = []
teamWins = []
teamDraws = []
teamLosses = []

#Populating lists with number of zeroes equal to the number of teams (one zero for each)
for x in range(leagueSize):
    teamPoints += [0]
    teamFor += [0]
    teamAgainst += [0]
    teamWins += [0]
    teamDraws += [0]
    teamLosses += [0]

#Entering names and skill ratings for each team
for i in range(leagueSize):
    teamNames += [input("Enter team "+str(i+1)+" name: ")]
for j in range(leagueSize):
    teamSkill += [input("Enter "+teamNames[j]+" skill: ")]

#Initialising variables
homeScore = 0
awayScore = 0

#The season begins - each team plays all of its home games in one go
for x in range(leagueSize):
    #input("Press enter to continue ")
    print("===========================================")
    print(teamNames[x]+"'s home games: ")
    print("===========================================\n")
    for y in range(leagueSize):
        error = 0
        try:
            homeScore = homeMatch(teamSkill[x],teamSkill[y])
        #Skipping a game to stop a team playing itself
        except ValueError:
            pass
            error += 1
        try:
            awayScore = awayMatch(teamSkill[x],teamSkill[y])
        except ValueError:
            pass
        if error == 0:
            #Updating lists
            print(teamNames[x],homeScore,"-",awayScore,teamNames[y],"\n")
            teamFor[x] += homeScore
            teamFor[y] += awayScore
            teamAgainst[x] += awayScore
            teamAgainst[y] += homeScore
            if homeScore > awayScore:
                teamWins[x] += 1
                teamLosses[y] += 1
                teamPoints[x] += 3
            elif homeScore == awayScore:
                teamDraws[x] += 1
                teamDraws[y] += 1
                teamPoints[x] += 1
                teamPoints[y] += 1
            else:
                teamWins[y] += 1
                teamLosses[x] += 1
                teamPoints[y] += 3
        else:
            pass

#Printing table (unsorted)
print("Final table: ")
for x in range(leagueSize):
    #Lots of formatting
    print(teamNames[x]+(15-len(teamNames[x]))*" "+" Skill: "+str(teamSkill[x])+(5-len(str(teamSkill[x])))*" "+" Points: "+str(teamPoints[x])+(5-len(str(teamPoints[x])))*" "+" For: "+str(teamFor[x])+(5-len(str(teamFor[x])))*" "+" Against: "+str(teamAgainst[x])+(5-len(str(teamPoints[x])))*" "+" Goal difference: "+str(teamFor[x]-teamAgainst[x])+(5-len(str(teamFor[x]-teamAgainst[x])))*" "+" Wins: "+str(teamWins[x])+(5-len(str(teamWins[x])))*" "+" Draws: "+str(teamDraws[x])+(5-len(str(teamDraws[x])))*" "+" Losses: "+str(teamLosses[x])+(5-len(str(teamLosses[x])))*" ")
teamPoints.sort()
print(teamPoints)

对不起,这很长,可能措辞不佳且效率低下,但我希望有人能够帮助我!非常感谢:)

【问题讨论】:

  • 您应该考虑使用不同的数据结构。您可以将所有数据保存在字典字典中,而不是尝试保持 3 个列表同步:{'team_name': {'wins': 1, 'draws': 1, 'loses': 0, 'points': 4}}
  • 啊,好主意,谢谢!

标签: python list sorting


【解决方案1】:

虽然您当前的方法(几乎)可行,但很难(例如)更改您要存储的有关每个团队的信息。您可以考虑改为定义一个 Team 类,该类的每个实例都存储有关特定团队的所有信息。

class Team:
    def __init__(self, name, skill):
        self.name = name
        self.skill = skill
        self.points = self.goals_for = self.goals_against = \
                     self.wins = self.draws = self.losses = 0

这使您可以通过传递名称和技能级别来创建新的团队对象,方式如下:

t1 = Team("Bradford City", 3)

t1 现在具有具有给定值的属性 nameskill,以及一些其他属性(pointsgoals_for 等),其值都为零。

然后你可以很容易地初始化联盟:

league_size = 4
teams = []
for _ in range(league_size):
    teams.append(Team(input("Name of team "+str(_)+": "),
                      int(input("Team "+str(_)+"'s skill level: ")))

然后要打印每个团队的技能水平,您可以遍历列表:

for team in teams:
    print(team.name, team.skill)

我希望这能让您了解如何简化您的方法。现在,您进行比赛的函数也可以将球队作为参数,并根据计算结果直接修改球队对象。

为了得到你想要的答案,一旦你有了一个团队列表,你就可以很容易地按照他们的得分排序打印出来:

for team in sorted(teams, key=lambda t: t.points):
    print(team.name, team.skill, team.points, ...)

据我所知,您的 global 声明都不是必需的(如果未在本地定义名称,Python 将寻找全局名称以满足引用)。除此之外,函数的输入通常应该作为参数传递,只是从环境中获取东西是相当糟糕的做法!

我希望这足以让您重新编写程序以使其更易于处理。作为一个初学者,我会说你已经做得非常好才能走到这一步。接下来的步骤会让您兴奋不已!

稍后添加:因此,您的 all-play-all 可能更容易编程:

for home in teams:
    for away in teams:
        if home is away: # Teams don't play themselves
            continue
        play_match(home, away)

play_match 函数将模拟比赛并调整每支球队的统计数据。当然你可以用另一条线来模拟客场比赛

         play_match(away, home)

虽然我不确定你的算法是否对称。

【讨论】:

  • 非常感谢您提供如此详细而有帮助的答案!我会尽快实现这一切!我们没有在计算机科学课程中学习课程,所以我以前从未尝试过它们。但是,是的,这看起来会大大简化程序!哈哈谢谢你,这个程序比第一个版本有数百行低效率改进了很多......无论如何,非常感谢你:)
  • 最好等到您通过经验发现其他表示问题的方法可能有缺点之后再学习类。你肯定已经学到了这一点!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-12
  • 1970-01-01
相关资源
最近更新 更多