如何在Python中按键对字典排序

32 投票
7 回答
129222 浏览
提问于 2025-04-16 09:40

有人能告诉我怎么把这个:

{'a': [1, 2, 3], 'c': ['one', 'two'], 'b': ['blah', 'bhasdf', 'asdf'], 'd': ['asdf', 'wer', 'asdf', 'zxcv']}

排序成这个:

{'a': [1, 2, 3], 'b': ['blah', 'bhasdf', 'asdf'], 'c': ['one', 'two'],'d': ['asdf', 'wer', 'asdf', 'zxcv']}

吗?谢谢!

更新 1,代码示例:

我在做语言学研究。一个文章被拆分成单词,这些单词存储在数据库里,并且有各种属性,比如段落ID和句子ID。我的任务是:试着重建原来的文本。

从数据库中获取500个连续的单词

words = Words.objects.all()[wordId:wordId+500]
# I first create paragraphs, through which I can loop later in my django template,
# and in each para will be a list of words (also dictionaries). 
# So i am trying to get a dictionary with values that are lists of dictionaries. 
# 'pp' i make just for shorthanding a long-named variable.
paras={}
para_high = para_low =  words[0].belongs_to_paragraph
for w in words:
    last_word = w
    pp = w.belongs_to_paragraph
    if pp >para_high:
        para_high = pp
    if pp < para_low:
        para_low = pp
    if pp in paras:
        paras[pp].append(w)
    else:
        list = [w]
        paras[pp] = list
# Since there are blank lines between paragraphs, in rebuilding the text as it 
    #  looked originally, I need to insert blank lines. 
    # Since i have the ID's of the paragraphs and they go somewhat like that: 1,3,4,8,9 
    #(the gaps between 1 & 3 and 4 & 8 i have to fill in with something else, 
    # which is why i had para_low and para_high to loop the range. 
isbr = True
for i in range(para_low, para_high+1):
    if i in paras:
        isbr = True
    else:
        if isbr:
            paras[i]=['break']
            isbr = False
        else:
            paras[i]=[]

但是到目前为止,如果我尝试循环这个字典并重建文本,有些后面的段落ID会出现在前面,这样就不对了。

更新 2,循环代码:

        {% for k,v in wording.iteritems()  %}
        {% if v[0] == 'break' %}
        <br/>
        {% else %}
        </div><div class="p">{% for word in v %}{% if word.special==0%} {% endif %}<span class="word {% if word.special == 0%}clickable{% endif%}" wid="{{word.id}}" special="{{word.special}}" somethingElse={{word.somethingElse}}>{{ word.word }}</span>{% endfor %}
        {% endif %}
    {% endfor %}

7 个回答

5

值得注意的是,Python有很多字典的实现方式,它们可以保持键的排序状态。比如有一个叫做 sortedcontainers 的模块,它是用纯Python写的,而且速度跟C语言一样快。这里还有一个 性能比较,可以看到它和其他一些快速且功能齐全的实现方式之间的对比。

举个例子:

>>> from sortedcontainers import SortedDict
>>> d = {'a': [1, 2, 3], 'c': ['one', 'two'], 'b': ['blah', 'bhasdf', 'asdf'], 'd': ['asdf', 'wer', 'asdf', 'zxcv']}
>>> s = SortedDict(**d)
>>> s.keys()
SortedSet(['a', 'b', 'c', 'd'])

你也可以完全用 SortedDict 来替代你使用的普通字典,因为它支持快速的获取和设置操作,并且可以按键进行排序遍历。

37

正确的做法是,如果你想要字典里的项目按顺序排列,你应该在遍历字典的时候使用 sorted() 函数:

for k, v in sorted(d.items()):
    print k, ':', v

或者

for k in sorted(d):
   print d[k]

或者类似的方式。

提到的 OrderedDict 是用来处理有顺序的字典。但顺序和排序是不一样的。你可以创建一个排序过的 OrderedDict,没错,但一旦你添加了新的键,它就不再是排序的了。所以你还是需要使用 sorted() 来在每次使用之前或者每次修改之后进行排序。 因此,OrderedDict 只会比普通字典慢,并且占用更多内存,但并没有提供你需要的功能。

OrderedDict 不是用来做排序的字典,而是用来处理那些有某种顺序的字典,这种顺序并不是排序。比如说,如果你想按添加的顺序显示东西,或者想让用户可以随意排序。

更新:进一步解释

为什么 OrderedDict 不是解决方案?因为 OrderedDict 是 有序的,而不是 排序的

考虑一个标准字典:

>>> d = {'a': 0, 'b': 1, 'c': 2, 'd': 3, 'e': 4, 'f': 5}

它并没有排序,正如我们下面看到的,'c' 会在 'b' 之前。它也没有顺序,如果我们添加新的东西,它的顺序看起来像是随机的:

>>> d['g'] = 6
>>> d['i'] = 8
>>> d
{'a': 0, 'c': 2, 'b': 1, 'e': 4, 'd': 3, 'g': 6, 'f': 5, 'i': 8}

好吧,那我们用 OrderedDict 吧:

>>> o = OrderedDict(sorted({'a': 0, 'b': 1, 'c': 2, 'd': 3, 'e': 4, 'f': 5}.items()))
>>> o
OrderedDict([('a', 0), ('b', 1), ('c', 2), ('d', 3), ('e', 4), ('f', 5)])

啊哈!排序了!所以 OrderedDict 有用!?不。

>>> o['i'] = 8
>>> o['g'] = 6
>>> o
OrderedDict([('a', 0), ('b', 1), ('c', 2), ('d', 3), ('e', 4), ('f', 5), ('i', 8), ('g', 6)])

什么?'g' 居然在 'i' 之后?!为什么!?因为 OrderedDict 不是排序的,它是 有序的。它记住的是你添加东西的 顺序,而不是排序。这意味着每次你使用它之前都需要先排序。OrderedDict 只会在你不添加新的键时保持排序。但如果你不打算修改它,那你就不需要字典。你完全可以用一个列表。这就是你从 sorted() 得到的:

>>> sorted(o.items())
[('a', 0), ('b', 1), ('c', 2), ('d', 3), ('e', 4), ('f', 5), ('g', 6), ('i', 8)]

但这在标准字典中也同样有效,所以 OrderedDict 并没有提供帮助:

>>> sorted(d.items())
[('a', 0), ('b', 1), ('c', 2), ('d', 3), ('e', 4), ('f', 5), ('g', 6), ('i', 8)]

结论

所以每次你想要以排序的方式遍历字典时,你都需要这样做:

>>> for k in sorted(o):
...   print k, o[k]
... 
a 0
b 1
c 2
d 3
e 4
f 5
g 6
i 8

而且这 无论你使用什么字典 都是如此。OrderedDict 并没有真正帮助你,因为它不关心 排序,只关心你添加东西的 顺序

62

字典是没有顺序的。

你可以使用排序功能,但这只是给你一个排序后的键的列表:

>>> sorted(d)
['a', 'b', 'c', 'd']

你可以把它当作一个可迭代对象,排序键值对的元组,但这样你得到的只是一个元组的列表。这和字典是不一样的。

>>> sorted(d.items())
[
 ('a', [1, 2, 3]),
 ('b', ['blah', 'bhasdf', 'asdf']),
 ('c', ['one', 'two']),
 ('d', ['asdf', 'wer', 'asdf', 'zxcv'])
]

如果你使用的是Python 2.7或更新的版本,你也可以考虑使用一个OrderedDict

这是一个字典的子类,它记住了添加条目的顺序。

比如:

>>> d = collections.OrderedDict(sorted(d.items()))
>>> for k, v in d.items():
>>>     print k, v
a [1, 2, 3]
b ['blah', 'bhasdf', 'asdf']
c ['one', 'two']
d ['asdf', 'wer', 'asdf', 'zxcv']

撰写回答