【问题标题】:Iterate dictionary (within dictionary) to sum up ranking迭代字典(字典内)总结排名
【发布时间】:2020-04-08 09:02:10
【问题描述】:

我得到以下列表,其中包含 4 个元组,每个玩家在 7 场比赛中的得分:

players_score  = [ ('Joe', 100, 34, 38, 90, 67, 3, 10),
                   ('Bob', 90, 38, 4, 100, 60, 4, 11),
                   ('May', 80, 36, 40, 91, 70, 2, 12),
                   ('Anna', 95, 32, 36, 92, 68, 8, 13) ]

由于我想了解更多有关字典的信息,我询问如何将上述内容转换为字典。我得到了以下信息:

# convert player's scores to dictionary
games = {}
for (player_name, *scores) in players_score:
    for game_no, score in enumerate(scores, 1):
        games.setdefault(game_no, {}).setdefault(player_name, {})
        games[game_no][player_name] = score

# the dictionary "games" will look like:

# {1: {'Anna': 95, 'Bob': 90, 'Joe': 100, 'May': 80},
#  2: {'Anna': 32, 'Bob': 38, 'Joe': 34, 'May': 36},
#  3: {'Anna': 36, 'Bob': 4, 'Joe': 38, 'May': 40},
#  4: {'Anna': 92, 'Bob': 100, 'Joe': 90, 'May': 91},
#  5: {'Anna': 68, 'Bob': 60, 'Joe': 67, 'May': 70},
#  6: {'Anna': 8, 'Bob': 4, 'Joe': 3, 'May': 2},
#  7: {'Anna': 13, 'Bob': 11, 'Joe': 10, 'May': 12}}

现在我正在尝试不同的方法来对每个玩家在每场比赛中的得分进行排名,然后将这些得分相加以返回如下内容:

{'Anna': 23, 'May': 18, 'Bob': 16, 'Joe': 15}

上面的分数是在返回每场比赛的排名总和时产生的。我让最好的玩家,每场比赛得分最高的获得4分,第二名获得3分,以此类推。

当然,像这样对第 1 场比赛的结果进行排序并不难:

score_list = []
for p in players_score:
    score_list.append(p[1])

score_list.sort(reverse=True)
print(score_list)

返回:[100, 95, 90, 80]

在列表/字典中搜索这些值,然后将点 (4/3/2/1) 添加到名称并最后总结它们会有什么好处吗?

【问题讨论】:

  • 当两个或更多玩家在某个回合中打成平手时,积分应该是多少?
  • 想用字典很好,但我的第一个想法是使用表格,可能是 Pandas。我也不完全确定我理解你的问题。
  • 安娜的分数不应该是20,鲍勃的分数是17

标签: python list dictionary enumerate


【解决方案1】:

试试这个:

from itertools import zip_longest as zilo
tt = list(sorted(i, reverse=True) for i in zilo(*[v for _, *v in players_score]))
# tt = [[100, 95, 90, 80], [38, 36, 34, 32], [40, 38, 36, 4], [100, 92, 91, 90], [70, 68, 67, 60], [8, 4, 3, 2], [13, 12, 11, 10]]

score_dict = {k : sum(4-j.index(i) for i,j in zip(v, tt)) for k, *v in players_score}

输出

{'Joe': 15, 'Bob': 17, 'May': 18, 'Anna': 20}

解释

首先,我们使用 zip_longestitertools 的元组获取每个游戏的分数:

zipped = list(zilo(*[v for _, *v in players_score]))

现在,zipped 是:

[(100, 90, 80, 95), (34, 38, 36, 32), (38, 4, 40, 36), (90, 100, 91, 92), (67, 60, 70, 68), (3, 4, 2, 8), (10, 11, 12, 13)]

检查第一项(元组)是第一场比赛的四个玩家的得分,依此类推。现在我们按降序对每个元组进行排序:

tt = list(sorted(i, reverse=True) for i in zipped)

所以,tt 现在变成了:

[[100, 95, 90, 80], [38, 36, 34, 32], [40, 38, 36, 4], [100, 92, 91, 90], [70, 68, 67, 60], [8, 4, 3, 2], [13, 12, 11, 10]]

现在,我们需要为每个玩家分配分数。我们可以像这样分解单行字典理解:

score_dict = {}
for k, *v in players_score:
    tmp = []
    for i,j in zip(v, tt):
        tmp.append(4-j.index(i)) #Change your score assigning logic here [5,3,1,0] in stead of [4,3,2,1]
    #print(tmp) #Check here for scores in each game for a player
    tot_score = sum(tmp)
    score_dict[k] = tot_score
#print(score_dict)

我们遍历players_score,我们将其中每个元组k的第一项作为玩家名称,其余作为另一个元组v(一个玩家在所有游戏中的得分),然后我们压缩这个元组v 和以前的tt,为每个特定游戏中的排名分配值。分配的分数是4-the_sorted_one_game_scores_tuple.index(particular_players_score_in_that_game),所有这些分数都被附加到每个玩家的临时列表中。在我们得到所有游戏的分数后,我们将它们相加,并将这个总和值 tot_score 作为值分配给 score_dict 字典的键 k

更新

您可以使用5-2*j.index(i) if 5-2*j.index(i) > 0 else 0 代替4-j.index(i)。请注意,在这种情况下,您必须有少于 5 场比赛,因为超过 5 场比赛会将最后一名球员和倒数第二名球员分配为零。如果您想推广此逻辑以将0,1,3,5,7,9,... 分配给更多人数;那么你就可以使用函数2*x-1 if 2*x-1 > 0 else 0 来生成这个数字序列。在这种情况下,在第二个 for 循环中进行更改,我们将分数附加到一个临时列表中,如下所示:

# To get 0,1,3,5,7,9,... type score
score_func = lambda x: 2*x-1 if 2*x-1>0 else 0
score_dict = {}
for k, *v in players_score:
    tmp = []
    for i,j in zip(v, tt):
        tmp.append(score_func(j.index(i)))
    tot_score = sum(tmp)
    score_dict[k] = tot_score
print(score_dict)

【讨论】:

  • 我仍在尝试完全理解您的代码,因此我想更改排名。我想让最好的玩家得到5分,第二个得到3分,第三个得到1分。第四个得到0分。以下公式适用 5-2*j.index(i) ,但我应该在哪里声明只有范围 [0:3] 适用?
  • 我(仍然)在用我的“逻辑”实现您的解决方案时遇到一些问题。用 5-2*j.index(i) 替换 4-j.index(i) 是解决方案的一部分,因为我没有添加该公式可能适用的“范围”。但是,我不太确定在这种情况下添加范围 ([0:3]) 是否是解决方案。
  • @JordivanSelm 更新了答案,请检查这是否是您所需要的。
  • 请在我的其他一个问题中查看第一个答案:stackoverflow.com/questions/59362077/… 在那里我得到了一个稍微简单的方法来解决这个问题。我刚刚修改了那里的代码,让程序在字典中打印结果。感谢您的意见!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-26
  • 2013-12-03
  • 1970-01-01
  • 1970-01-01
  • 2013-10-15
相关资源
最近更新 更多