How to iterate with range using itertools?

百般思念 提交于 2020-01-06 04:51:05

问题


Considering the following list within it 4 tuples:

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) ]

The players have been playing 7 games. In the first game, Joe has won with 100 points.

I would like to score each player (of each game) according to the following:

First/best player: 5 points
Second player: 3 points
Third player: 1 point
Fourth player: -1 point -> But 0 points is what I like to assign the fourth player of each game.

My code so far:

from itertools import zip_longest as y

zipped = list(y(*[game_score for _, *game_score in players_score]))
tup = list(sorted(i, reverse=True) for i in zipped)
score_dict = {}
for player, *game_score in players_score:
    tmp = []
    for i,j in zip(game_score, tup):
        tmp.append(5-2*j.index(i))
    tot_score = sum(tmp)
    score_dict[player] = tot_score

print("The overall scores are: ", sorted(score_dict.items(), key=lambda kv: (kv[1], kv[0]), reverse=True))

So, my code applies -1 points to the fourth player of each game, but instead, I want the fourth player to earn just 0 zero points. I'm struggling with applying a range ([0:3]) or another method by which I could skip the fourth player from getting a score because that player just earns 0 points.


回答1:


I would set this up a bit differently. That being said, there's more than one way to do this. The first thing I would do is turn that players_score list into a prettier collection, like a dictionary - just so it's more fun to work with.

Basically, we iterate through our "rounds" (the games), and sort the player names based on their score in the current round (the winner of the current round comes first). Then we zip the sorted player names with the respective reward (score) they deserve, and update our collections.Counter collection, using the player name as the key.

from collections import Counter

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)
]

original_scores = {player: scores for player, *scores in players_score}

def iter_score(player):
    for score in original_scores[player]:
        yield player, score

score_rewards = [5, 3, 1, 0]

overall_scores = Counter()

for current_round in zip(*map(iter_score, original_scores)):
    sorted_players = map(lambda tpl: tpl[0], sorted(current_round, key=lambda tpl: tpl[1], reverse=True))
    for player, score in zip(sorted_players, score_rewards):
        overall_scores.update({player: score})

print("The overall scores:")
for player, score in overall_scores.most_common():
    print(f"{player}: {score}")

Output:

The overall scores:
Anna: 20
May: 17
Bob: 15
Joe: 11



回答2:


you can change your scoring function:

tmp.append(5-2*j.index(i) if 5-2*j.index(i) > 0 else 0)

so if there is negative values set the score to 0




回答3:


A very simple solution

for i,j in zip(game_score, tup):
        score_var = 5-2*j.index(i)
        if (score_var < 0):
              score_var = 0
        tmp.append(score_var)

This will ensure that no player will earn negative points.




回答4:


Use max(0, x) to ensure that the value is at least 0:

tmp.append(max(0, 5-2*j.index(i)))


来源:https://stackoverflow.com/questions/59362077/how-to-iterate-with-range-using-itertools

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!