1

我正在尝试为班级的一个小琐事游戏创建一个高分列表。我遇到了一个问题,因为我似乎无法让打印输出不只是随机打印字典。这个片段实际上并不是来自完整的程序,因为我不想破坏任何东西,所以它只是试图推理出这个函数。

scores = {'score1': {'initials': 'ywo',
                     'score': 20},
          'score2': {'initials': 'JRV',
                     'score': 18},
          'score3': {'initials': 'blh',
                     'score': 16},
          'score4': {'initials': 'yth',
                     'score': 15},
          'score5': {'initials': 'rtg',
                     'score': 12}}

total_score = 17


#iterates over the scores to see if new score and initials should be input
for i in (scores):
        if total_score > scores[i]['score']:
        scores[i]['initials'] = 'JKE'
        scores[i]['score'] = total_score
        break

#prints scores in a table like format rather than list
print("HIGH\tSCORES")
for i in scores:
    print(scores[i]['initials'], "\t", scores[i]['score'])

我的输出每次都是随机的。我只希望字典按从高到低的顺序打印,例如:

ywo    20 
JRV    18 
JKE    17

等等等等

我遇到的另一个问题是我不确定如何将字典中的其他分数降低。因此,如果 JKE 的分数替换了 blh 的分数,那么 blh 不仅会从字典中删除,而且会向下移动到 score4 索引,并且 score4 值将移动到 score5 等等。我感谢任何建议!谢谢!

4

7 回答 7

1

我认为您可能试图使这有点过于复杂(尽管这听起来像是家庭作业,所以这可能是一项要求)。

我会这样处理它:

scores = {'YWO': 20,
          'BLH': 16,
          'YTH': 15,
          'JRV': 18,
          'RTG': 12,
         }


def display_scores(scores):
    for score, name in sorted(((scores[k], k) for k in scores, reverse=True):
        print(name, score)

然后您可以通过以下方式轻松添加球员和分数:

scores[initials] = scores.get(initials, 0) + 1 #or points or whatever
于 2013-10-15T18:50:07.843 回答
0

字典以任意顺序存储。如果要对输出进行排序,则必须手动进行。由于您有键score1,score2等碰巧按正确的顺序排序,因此您可以这样做:

for i in sorted(scores):
    print(scores[i]['initials'], "\t", scores[i]['score'])

但是,您的代码实际上似乎并没有正确维护该字典。当您找到一个分数 beats 的用户时score2,您只需score2用新分数替换,而不是将其推低score3等等。

而且我不确定你为什么要首先以这种方式存储分数。如果你想维护一个订单,为什么不直接使用 key 0through 4in alist而不是score1through score5in adict呢?例如:

scores = [{'initials': 'ywo',
           'score': 20},
          {'initials': 'JRV',
           'score': 18},
          {'initials': 'blh',
           'score': 16},
          {'initials': 'yth',
           'score': 15},
          {'initials': 'rtg',
           'score': 12}]

for i, score in enumerate(scores):
    if total_score > score['score']:
        scores[i:i+1] = {'initials': 'JKE', 'score': total_score}
        del scores[5:]
        break

现在,它们总是按排序顺序排列:

for score in scores:
    print(score['initials'], "\t", score['score'])

您可以使用heapq. 但是,这有点复杂,因为 aheapq通过比较值本身来保持它的值排序,但您希望它比较 on value['score']。与 Python 中大多数与排序相关的功能不同,heapq它没有key使这变得简单的功能。所以,你必须做一些手动的“装饰-排序-取消装饰”工作:

decorated_scores = [(score['score'], score) for score in scores]
heapify(decorated_scores)

现在,添加一个新的高分:

new_score = (total_score, {'initials': 'JRV', 'score': total_score})
dropped_off = heappushpop(decorated_scores, new_score)
if dropped_off == new_score:
    # didn't make the high scores
else:
    # did

另一种简化的方法是使用自动排序列表,比如文档中SortedCollection引用的配方bisect,或者像blist.sortedlist.

于 2013-10-15T18:37:50.407 回答
0

字典是一种非排序类型,因此每次都期望顺序每次都会更改是合理的。

我认为你应该考虑不同的数据类型来处理这个问题(这也回答了你问题的第二部分)。

我认为您应该考虑订购字典 - http://docs.python.org/2/library/collections.html

或者我认为对此目的更好的东西 - http://docs.python.org/2/library/heapq.html

于 2013-10-15T18:39:10.133 回答
0

你需要以某种方式保持你的分数有序。最好的方法是保持有序列表。您可以使用该bisect模块来帮助您执行此操作。bisect.bisect(list, item)返回您应该插入item到列表中的索引,以便列表仍然排序。如果我们将分数保留为(score, name)元组列表,则默认的元组比较将起作用 - 较小的分数将首先出现,较大的分数在最后。我们可以每次删除除最后五个元素之外的所有元素,只保留前 5 个分数。

def add_score(scores, name, score):
    new_item = (score, name)
    scores.insert(bisect.bisect(scores, new_item), new_item)
    del scores[:-5] #keep only the top 5 scores

要打印它们,我们反转列表:

def print_scores(scores):
    for score, name in reversed(scores):
        print "%s\t%s" % (name, score)

用法:

>>> scores = []
>>> add_score(scores, "fool", 10)
>>> scores
[(10, 'fool')]
>>> add_score(scores, "jimbo", 100)
>>> scores
[(10, 'fool'), (100, 'jimbo')]
>>> add_score(scores, "bob", 20)
>>> scores
[(10, 'fool'), (20, 'bob'), (100, 'jimbo')]
>>> add_score(scores, "ha", 3)
>>> scores
[(3, 'ha'), (10, 'fool'), (20, 'bob'), (100, 'jimbo')]
>>> add_score(scores, "bob", 200)
>>> add_score(scores, "bob", 140)
>>> add_score(scores, "bob", 50)
>>> scores
[(20, 'bob'), (50, 'bob'), (100, 'jimbo'), (140, 'bob'), (200, 'bob')]
>>> print_scores(scores)
bob 200
bob 140
jimbo   100
bob 50
bob 20
于 2013-10-15T18:39:24.060 回答
0

字典不维护任何特定的顺序,如果您使用 OrderedDict,它会。

from collections import OrderedDict
d = OrderedDict([('first', 1),('second', 2),('third', 3)])
print d.items()

输出:

[('first', 1), ('second', 2), ('third', 3)]
于 2013-10-15T18:35:58.633 回答
0

我会使用字典列表,然后您可以轻松地对分数进行排序,例如仅显示最佳 3。列表的格式可以是:[{score:player},...]

于 2013-10-15T18:42:38.103 回答
0

我认为可能有比您拥有的更好的数据结构开始,我只做了一次调整,将您的键设置为字典整数,这将解决您的打印问题,该功能将建立一个新的排行榜,最大值为 5条目,并将新分数放在它所属的位置。如果出现平局,则提交的第二个分数将进入输入位置中较低的分数。分数必须超过最低分数才能进入棋盘。

scores = {1: {'initials': 'ywo',
                 'score': 20},
      2: {'initials': 'JRV',
                 'score': 18},
      3: {'initials': 'blh',
                 'score': 16},
      4: {'initials': 'yth',
                 'score': 15},
      5: {'initials': 'rtg',
                 'score': 12}}
def new_leaderboard(new_score,new_initials):
   going_down_a_place = []
   place_found = False
   existing_scores = scores.copy()
   for i in scores:
       if new_score > scores[i]['score'] and place_found == False:
           leaderboard_placement = i
           place_found = True
       if new_score > scores[i]['score']:
           going_down_a_place.append(i)
   if len(going_down_a_place) > 0:
       going_down_a_place.remove(max(going_down_a_place))

   for val in going_down_a_place:
       place = val + 1
       scores[place] = {'initials':existing_scores[val]['initials'],'score':existing_scores[val]['score']}
   if place_found == True:
       scores[leaderboard_placement] = {'initials':new_initials,'score':new_score}

   for i in scores:
       print(scores[i]['initials'], "\t", scores[i]['score'])
new_score = 21
new_initials = 'ddd'
new_leaderboard(new_score,new_initials)
于 2015-06-15T21:20:19.007 回答