字典是否跟踪项目分配的时间点?

时间:2013-07-26 23:13:17

标签: python dictionary

我正在编写一个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()

3 个答案:

答案 0 :(得分:1)

没有。您得到的结果是由dict实现内部的任意选择引起的,您不能总是依赖它。 (有一个dict的子类确实跟踪了插入顺序,但是:collections.OrderedDict。)我相信,对于当前的实现,如果切换PL1和PL2行的顺序,PL1将可能仍然会被删除。

答案 1 :(得分:1)

正如其他人所说,字典中的项目顺序是“直到实现”。

这个答案更像是对你的问题的评论,“min()如何决定什么分数最低?”,但是太长了,格式为评论。 : - )

有趣的是maxmin都可以这样使用。原因是他们(可以)处理“iterables”,并且字典是可迭代的:

for i in some_dict:

在字典中的所有键上循环i。在您的情况下,键是用户名。此外,minmax允许传递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适用于保留插入顺序,但不适用于键顺序。