Python字典无法保持顺序

5

我创建了一个字母表的字典,其值从0开始,并根据单词文件增加一定数量。我硬编码了最初的字典,并希望它保持字母顺序,但实际上并没有。我希望它以字母顺序返回字典,基本上与最初的字典保持相同。

如何保持其顺序?

from wordData import*

def letterFreq(words):
    
    totalLetters = 0
    letterDict = {'a':0,'b':0,'c':0,'d':0,'e':0,'f':0,'g':0,'h':0,'i':0,'j':0,'k':0,'l':0,'m':0,'n':0,'o':0,'p':0,'q':0,
                  'r':0,'s':0,'t':0,'u':0,'v':0,'w':0,'x':0,'y':0,'z':0}

    for word in words:
        totalLetters += totalOccurences(word,words)*len(word)
        for char in range(0,len(word)):
            for letter in letterDict:
                if letter == word[char]:
                    for year in words[word]:
                        letterDict[letter] += year.count
    for letters in letterDict:
        letterDict[letters] = float(letterDict[letters] / totalLetters)
    print(letterDict)
    return letterDict

def main():
   
    filename = input("Enter filename: ")
    words = readWordFile(filename)
    letterFreq(words)


if __name__ == '__main__':
    main()

我觉得 for year in words[word]: letterDict[letter] += year.count 这段代码非常令人困惑。你能详细解释一下这段代码的作用吗?另外,float(letterDict[letters] / totalLetters) 可能不会像你想象的那样工作。 - jpmc26
2
可能是[Python字典,保持键/值与声明的顺序相同]的重复问题(https://dev59.com/LHI-5IYBdhLWcg3wZ3nC) - Zulu
4个回答

16

Python 3.7+ 更新:

从 Python 3.7 开始,字典现在官方维护插入顺序


Python 3.6 更新:

在 Python 3.6 中,字典维护插入顺序。但是,这被视为一个实现细节,不应该依赖它


Python 3.5 及之前版本的原始回答:

字典是无序的,不会为你保留任何顺序。

您可以使用有序字典来维护插入顺序:

from collections import OrderedDict
letterDict = OrderedDict([('a', 0), ('b', 0), ('c', 0)])

或者您可以只返回您的字典内容排序后的列表。

letterDict = {'a':0,'b':0,'c':0}
sortedList = sorted([(k, v) for k, v in letterDict.iteritems()])

print sortedList # [('a', 0), ('b', 0), ('c', 0)]

5
值得注意的是:OrderedDict 不是一个 排序 字典,它的顺序是插入顺序,如果我没记错的话。 - jpmc26
有没有办法返回一个按字母顺序排列的列表或另一个字典? - Cos
1
我想点赞,但你的声望恰好是1000分,这很酷。 - en_Knight

2
您只需要按一次键,所以:
# create letterDict as in your question    
keys = list(letterDict)
keys.sort()
for key in keys:
    # do whatever with letterDict[key]

如果您需要多次按顺序使用它们,可以使用标准库的collections.OrderedDict。有时这就是您所需的全部。它按添加顺序保留字典键的顺序。
如果您真正需要一个按键排序的字典类型,并且您不仅需要一次(其中list_.sort()更好),则可以尝试其中之一: http://stromberg.dnsalias.org/~dstromberg/datastructures/ 关于上面的链接,如果您的键以已排序的顺序添加,那么最好使用treap或红黑树(在平均情况下treap更好,但是红黑树具有较低的标准差)。如果您的键总是以随机顺序添加,则简单的二叉树更好。
顺便说一句,目前的流行趋势似乎倾向于sorted(list_)而不是list_.sort(),但是sorted(list_)是语言中相对较新的添加,在添加之前我们很好地处理了它,而且它稍微慢一些。此外,list_.sort()不会像sorted(list_)一样导致一行滥用。
哦,而且普通的字典是无序的 - 这就是为什么它们快速访问任意元素(它们建立在哈希表上)的原因。我提供的datastructures URL中的一些类型很擅长dict_.find_min()和dict_.find_max(),可以避免keys.sort(),但它们在访问任意元素时较慢(logn)。

1
你可以对字典的键进行排序并迭代字典。
>>> for key in sorted(letterDict.keys()):
...     print ('{}: {}').format(key, letterDict.get(key))
...
a: 0
b: 0
c: 0
d: 0
e: 0
...

或者

这可能是您情况下的一个解决方案。我们可以将所有您的字典键放在列表中,其顺序不会改变,然后我们可以按照该顺序从您的字典中获取值。

>>> import string
>>> keys = list(string.ascii_lowercase)
>>> letterDict = {'a':0,'b':0,'c':0,'d':0,'e':0,'f':0,'g':0,'h':0,'i':0,'j':0,'k':0,'l':0,'m':0,'n':0,'o':0,'p':0,'q':0,
...                   'r':0,'s':0,'t':0,'u':0,'v':0,'w':0,'x':0,'y':0,'z':0}
>>> for key in keys:
...      if key in letterDict:
...         print ('{}: {}').format(key, letterDict.get(key))
...
a: 0
b: 0
c: 0
d: 0
e: 0
f: 0
g: 0
h: 0
i: 0
j: 0
k: 0
l: 0
m: 0
....

这实际上是一个不错的解决方案,尽管有点天真(只有在您已经事先知道键的情况下才能工作)。但是,通过检查字典键并在访问它们之前对它们进行排序,可以将其扩展。即便如此,仍然远非理想,因为通过预先实例化键列表来占用内存。 - Pablo Mescher
@PabloMescher 我只是想展示一种可能的解决方案,因为我们在网上有很多解决方案(Orderdict, operators等)。但我同意如果字典被更新,这种方法在内存方面并不高效。 - Tanveer Alam

0
我不会这样实现。它很难阅读。更好的方式是这样:
# Make sure that division always gives you a float
from __future__ import division
from collections import defaultdict, OrderedDict
from string import ascii_lowercase

...

    letterDict = defaultdict(int)

    ...

        # Replace the for char in range(0,len(word)): loop with this
        # Shorter, easier to understand, should be equivalent
        for year in words[word]:
            for char in word:
                letterDict[char] += year.count

    ...

    # Filter out any non-letters at this point
    # Note that this is the OrderedDict constructor given a generator that creates tuples
    # Already in order since ascii_lowercase is
    letterRatio = OrderedDict((letter, letterDict[letter] / totalLetters) for letter in ascii_lowercase)
    print(letterRatio)
    return letterRatio

...

现在您将返回一个 OrderedDict,顺序将被保留。但我要警告您。如果您确实需要在某个时候按顺序排列,那么只需在需要正确顺序时进行排序即可。不要依赖计算新数据的函数以特定排序顺序返回内容。在需要排序时再进行排序,而不是在之前。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接