我正在编写一个High Scores系统,用户可以输入一个名称和一个分数,然后程序将测试该分数是否大于high_scores中的最低分数。如果是,则写入分数并删除最低分数。一切都很好,但我注意到了一些事情。 high_scores.txt
文件是这样的:
PL1 50
PL2 50
PL3 50
PL4 50
PL5 50
PL1是第一个得分,PL2是第二个,PL3是第三个,依此类推。然后我尝试添加另一个分数,高于所有其他分数(PL6 60),发生的是该程序将PL1指定为最低分数。添加PL6并删除PL1。这正是我想要的行为,但我不明白它是如何发生的。字典是否跟踪项目分配的时间点?这是代码:
MAX_NUM_SCORES = 5
def getHighScores(scores_file):
"""Read scores from a file into a list."""
try:
cache_file = open(scores_file, 'r')
except (IOError, EOFError):
print("File is empty or does not exist.")
return []
else:
lines = cache_file.readlines()
high_scores = {}
for line in lines:
if len(high_scores) < MAX_NUM_SCORES:
name, score = line.split()
high_scores[name] = int(score)
else:
break
return high_scores
def writeScore(file_, name, new_score):
"""Write score to a file."""
if len(name) > 3:
name = name[0:3]
high_scores = getHighScores(file_)
if high_scores:
lowest_score = min(high_scores, key=high_scores.get)
if new_score > high_scores[lowest_score] or len(high_scores) < 5:
if len(high_scores) == 5:
del high_scores[lowest_score]
high_scores[name.upper()] = int(new_score)
else:
return 0
else:
high_scores[name.upper()] = int(new_score)
write_file = open(file_, 'w')
while high_scores:
highest_key = max(high_scores, key=high_scores.get)
line = highest_key + ' ' + str(high_scores[highest_key]) + '\n'
write_file.write(line)
del high_scores[highest_key]
return 1
def displayScores(file_):
"""Display scores from file."""
high_scores = getHighScores(file_)
print("HIGH SCORES")
if high_scores:
while high_scores:
highest_key = max(high_scores, key=high_scores.get)
print(highest_key, high_scores[highest_key])
del high_scores[highest_key]
else:
print("No scores yet.")
def resetScores(file_):
open(file_, "w").close()
答案 0 :(得分:1)
没有。您得到的结果是由dict
实现内部的任意选择引起的,您不能总是依赖它。 (有一个dict
的子类确实跟踪了插入顺序,但是:collections.OrderedDict
。)我相信,对于当前的实现,如果切换PL1和PL2行的顺序,PL1将可能仍然会被删除。
答案 1 :(得分:1)
正如其他人所说,字典中的项目顺序是“直到实现”。
这个答案更像是对你的问题的评论,“min()
如何决定什么分数最低?”,但是太长了,格式为评论。 : - )
有趣的是max
和min
都可以这样使用。原因是他们(可以)处理“iterables”,并且字典是可迭代的:
for i in some_dict:
在字典中的所有键上循环i
。在您的情况下,键是用户名。此外,min
和max
允许传递key
参数以将迭代中的每个候选变为适合二进制比较的值。因此,min
几乎等同于以下python代码,其中包括一些跟踪以准确显示其工作原理:
def like_min(iterable, key=None):
it = iter(iterable)
result = it.next()
if key is None:
min_val = result
else:
min_val = key(result)
print '** initially, result is', result, 'with min_val =', min_val
for candidate in it:
if key is None:
cmp_val = candidate
else:
cmp_val = key(candidate)
print '** new candidate:', candidate, 'with val =', cmp_val
if cmp_val < min_val:
print '** taking new candidate'
result = candidate
return result
如果我们在示例字典d
上运行上述内容,请使用d.get
作为key
:
d = {'p': 0, 'ayyy': 3, 'b': 5, 'elephant': -17}
m = like_min(d, key=d.get)
print 'like_min:', m
** initially, result is ayyy with min_val = 3
** new candidate: p with val = 0
** taking new candidate
** new candidate: b with val = 5
** new candidate: elephant with val = -17
** taking new candidate
like_min: elephant
我们发现我们得到的值是最小的键。当然,如果多个值相等,“最小”的选择取决于字典迭代顺序(以及min
是否实际在内部使用<
或<=
。
(另外,用于“排序”高分以打印出来的方法是O(n 2 ):选择最高值,从字典中删除它,重复直到空。这遍历n项,然后n-1,...然后2,然后1 =&gt; n +(n-1)+ ... + 2 + 1步= n(n + 1)/ 2 = O(n 2 )。删除高一个也是一个昂贵的操作,虽然它应该仍然在O(n 2 )或者在O(n 2 )之下。我认为。当n = 5时,这不是那个坏(5 * 6/2 = 15),但......不优雅。:-))
答案 2 :(得分:0)
这几乎是http://stromberg.dnsalias.org/~strombrg/python-tree-and-heap-comparison/的内容。
简短版本:获取treap模块,其工作方式类似于排序字典,并保持按键顺序。或者使用嵌套模块自动获取n个最大(或最小)值。
collections.OrderedDict适用于保留插入顺序,但不适用于键顺序。