【问题标题】:why is my dictionary ordered in python?为什么我的字典是用 python 排序的?
【发布时间】:2014-06-19 18:13:50
【问题描述】:

我想看看一个词在 twitter 的推文中出现的频率。我使用 Twitter API 从 twitter 下载了 500 条推文,并制作了一个字典,其中词频为键,与该频率对应的所有词的列表为值。

我一直认为字典总是无序的,所以我想以某种方式订购我的字典。但是当我看它时,它已经按从低到高的键顺序排列了。这怎么可能?

这是我使用的代码:

def countWords(cleanDict): 
    reverseDict = {}
    FreqDict = {}
    count = 1
    for tweet_id in cleanDict:
        tweet = cleanDict[tweet_id]
        wordList = tweet.split()
        for word in wordList: # Creates a dictionary with words as keys and
                              # frequencies as values
            if word in reverseDict:
                reverseDict[word] += 1
            else:
                reverseDict[word] = 1
    for word in reverseDict: # Creates a dictionary with frequencies as keys and
                             # lists of words as values
        if reverseDict[word] in FreqDict:
            temp = FreqDict[freqDict[word]]
            temp.append(word)
            FreqDict[freqDict[word]] = temp
        else:
            FreqDict[freqDict[word]] = [word]
    return FreqDict

countWords(cleanDict) # cleanDict is a dictionary with tweet ID's as keys and
                      # tweets as values

不要误会我的意思,我的字典已经被这样排序真是太好了,但是如何呢? 是我添加到字典的方式还是什么?

编辑

我尝试制作一个以整数为键、一些字符串为值的字典。我没有按特定顺序添加键,但是当我打印这本字典时,它再次按键排序。 这是python总是做的事情吗?

【问题讨论】:

  • 它们的下载顺序是什么?
  • 你怎么知道它被订购了?你在哪里看?它是如何显示的?底层表示是无序的,但这并不意味着其他东西不能以有序的方式表示它。
  • @Drewdin 下载的最后一条推文是发布的最后一条推文。最后下载的第二条是最后一条推文发布的第二条推文,依此类推,一直到第 500 条推文
  • @g.d.d.c 我刚刚将它打印到我的 shell

标签: python dictionary


【解决方案1】:

“无序”是用词不当 - 它们是任意有序的,由实现决定。具体来说,保证顺序是任意的,但一致(在 python 解释器 [1] 的单个实例中)。

至于您为什么会出现这种行为 - 您正在使用 ints 作为您的密钥。碰巧在 cPython 中,inthash 就是它自己。因此:

d = dict(zip(range(100),' '*100))
print(d)

由于实现细节,将始终按数字顺序显示键。但是这个:

d = dict((L, i) for i, L in enumerate('abcdefg'))
print(d)

(很可能)不会按字母顺序打印出来。


[1] 字符串散列行为可以因解释器实例而异,具体取决于您运行的 python 版本。 Python 3 为字符串键的散列引入了“随机种子”,作为一种安全措施。您可以使用 python -R 在 python 2.7 上启用该行为。

【讨论】:

  • 值得注意的是,即使使用整数,只有当您的数字相对紧凑并且从零开始时,您才有可能获得准确的排序。如果您在示例中使用与0100 不同的范围,您可能会或可能不会以有序键结束。例如dict(zip(range(200, 300), " "*100)),以256 开头,而不是200
  • 哦,真奇怪。我没有意识到它在 Python 2 中的工作方式不同。它在 Python 3 中发生的原因是哈希(等于键)与底层哈希表大小的精确倍数相交。实际的哈希表索引是哈希,修改表大小,所以这意味着一些值最终会乱序。我怀疑在 Python 2 中可能会以某种方式发生同样的事情,除非有一些我不知道的故意 hack 让它保持有序。使用分布非常广泛的数字,由于哈希冲突,您可能会得到奇怪的订单!
  • @Blckknght 有趣。我在一夜之间想到了这一点,你是对的 - 对于 py3 中的小字典,排序似乎与 key % 256 一致,即 8 位哈希表。我刚刚检查了一下,下一步是一个 10 位表,所以key % 1024。所以真正的异常是python 2 - 我很好奇继续调查,如果我自己无法弄清楚,可能会发布一个问题。
  • 啊,就是这样 - dict(zip(range(1000,2100), ' '*1100)) 似乎在 python 2 中表现出 key % 2048 排序。所以实际上只是哈希表在 py2 中从 11 位开始,在 py3 中从 8 位开始。唷。
  • 它随您放入字典中的值的数量而变化。尝试使用少于 6 个项目和 7 和 8 键的 dict,在 Python 2 和 3 中迭代时,你会在 7 之前得到 8。我认为我们在版本之间看到的差异与确切的位置有关边界是导致内部哈希表调整大小(或者可能是调整大小的表变得多大)。
【解决方案2】:

可能纯属运气。如果您在 dict 中有更多对象并且需要调整大小,或者您的对象不是一个接一个地创建(因此它们的 ID/内存地址变化更大),则可能会发生变化。

如果您需要订单,您可以简单地使用collections.OrderedDict 并得到保证。或者使用collections.Counter 来完成任务,这是为这种计数而设计的。

【讨论】:

  • 不可能只是纯粹的运气吧?如果有 10 条推文,那么字典中的顺序实际上是有序的可能性很小,但是 500?
猜你喜欢
  • 2013-02-04
  • 2011-09-17
  • 2019-01-21
  • 1970-01-01
  • 2013-05-01
相关资源
最近更新 更多