如何按键对字典进行排序?

1489

如何根据字典的键进行排序?

示例输入:

{2:3, 1:89, 4:5, 3:0}

期望的输出:

{1:89, 2:3, 3:0, 4:5}

6
我的使用场景是我有一个CLI应用程序,它有一个简单的菜单,菜单选项作为字典键存在。我想按字母顺序显示这些键,以使用户更加方便使用。 - Randy
2
“字典未排序” - 并非普遍真实。例如,Java拥有TreeMap(https://docs.oracle.com/javase/8/docs/api/java/util/TreeMap.html),它的行为完全符合OP的要求。 - Nayuki
14
请注意,字典现在按照插入顺序排序(Python 3.6+)。以下部分答案指出了这一点。 - matiasg
4
请注意,在Python 3.6中,保持插入顺序的字典是CPython的一个实现细节。直到Python 3.7,字典的插入顺序保持才正式成为语言的一部分。 - robertspierre
排序后的字典 = dict(sorted(my_dict.items())) - undefined
33个回答

1284

注意: 对于Python 3.7+,请参见此答案

标准的Python字典是无序的(在Python 3.7之前)。即使您对(键,值)对进行了排序,也无法以保留排序方式的方式将它们存储在dict中。

最简单的方法是使用OrderedDict,它可以记住元素插入的顺序:

In [1]: import collections

In [2]: d = {2:3, 1:89, 4:5, 3:0}

In [3]: od = collections.OrderedDict(sorted(d.items()))

In [4]: od
Out[4]: OrderedDict([(1, 89), (2, 3), (3, 0), (4, 5)])

不用在意od的输出方式;它会按预期运行:

In [11]: od[1]
Out[11]: 89

In [12]: od[3]
Out[12]: 0

In [13]: for k, v in od.iteritems(): print k, v
   ....: 
1 89
2 3
3 0
4 5

Python 3

对于Python 3用户,需要使用.items()代替.iteritems()

In [13]: for k, v in od.items(): print(k, v)
   ....: 
1 89
2 3
3 0
4 5

7
如果那个方法奏效了,那肯定是纯属运气。正如你所说,无论你是按照顺序还是随意给键赋值,普通的字典都没有排序的概念。 - Ricardo Cárdenes
251
对于 Python 3.7+:sorted_dict = dict(sorted(unsorted_dict.items())) 可以将未排序的字典转换为已排序的字典。 - aksh1618
45
Python 3.7+不再需要使用OrderedDict,因为默认情况下会自动进行排序 :-) - Andrew Bowman
10
从Python 3.7.4手册上可以得知:"对一个字典执行list(d)操作,将返回该字典中使用过的所有键的列表,按照插入顺序排序"。因此,插入顺序是被保留下来的,我们可以信任它。 - Mostafa Hadian
5
OrderedDict 只是一种半解决方案,因为它维护插入的顺序。因此,无法从空字典开始添加项并期望键按排序顺序排列。相反,只能在所有项被填充后才能在现有字典上使用 OrderedDict 结构,因为其仅按插入顺序工作,而不是按预期进行任何类型的排序。 - demongolem
显示剩余10条评论

576

对于CPython/PyPy 3.6,以及任何Python 3.7或更高版本,可以轻松完成以下操作:

>>> d = {2:3, 1:89, 4:5, 3:0}
>>> dict(sorted(d.items()))
{1: 89, 2: 3, 3: 0, 4: 5}

42
另一种写法是使用推导式: {key: d[key] for key in sorted(d.keys())} - flow2k
2
这是一个很好的答案。但不要尝试用{}sorted括起来,例如{sorted(d.items())},以使它更短。那只会尝试创建一个集合。 - ChaimG
5
@flow2k的答案(使用“推导式”)可以简化成以下形式: {key:d[key] for key in sorted(d)}, 因为sorted(d)返回了一个按键排序后的列表。 - Julian - BrainAnnex.org
我在Python3.8中使用sorted(d.items())而无需使用dict() - Timo
5
@Timo sorted(d.items()) 返回的是已排序的键值对可迭代对象,而不是字典。 - Dipu

512

词典本身并没有顺序,如果您想要按照某种顺序打印它们,以下是一些示例:

在Python 2.4及以上版本中:

mydict = {'carl':40,
          'alan':2,
          'bob':1,
          'danny':3}

for key in sorted(mydict):
    print "%s: %s" % (key, mydict[key])

提供:

alan: 2
bob: 1
carl: 40
danny: 3

(Python 版本低于 2.4:)

keylist = mydict.keys()
keylist.sort()
for key in keylist:
    print "%s: %s" % (key, mydict[key])

来源: http://www.saltycrane.com/blog/2007/09/how-to-sort-python-dictionary-by-keys/


2
在Python 2.4+中,您也可以像NPE的回答一样使用OrderedDict。 - radtek
2
如果您正在使用items(),您可以这样做:for key, value in sorted(mydict.items())" - beep_check
5
字典本身并没有所谓的有序项目。-> 不再正确! - minexew
怎么回事,你能解释一下吗? - James
@James 请查看链接 - SearchSpace

232

来自Python的collections库文档

>>> from collections import OrderedDict

>>> # regular unsorted dictionary
>>> d = {'banana': 3, 'apple':4, 'pear': 1, 'orange': 2}

>>> # dictionary sorted by key -- OrderedDict(sorted(d.items()) also works
>>> OrderedDict(sorted(d.items(), key=lambda t: t[0]))
OrderedDict([('apple', 4), ('banana', 3), ('orange', 2), ('pear', 1)])

>>> # dictionary sorted by value
>>> OrderedDict(sorted(d.items(), key=lambda t: t[1]))
OrderedDict([('pear', 1), ('orange', 2), ('banana', 3), ('apple', 4)])

>>> # dictionary sorted by length of the key string
>>> OrderedDict(sorted(d.items(), key=lambda t: len(t[0])))
OrderedDict([('pear', 1), ('apple', 4), ('orange', 2), ('banana', 3)])

9
太棒了!如果你想要反转顺序(从升序变为降序),你只需要添加reverse=True,例如OrderedDict(sorted(d.items(), reverse=True, key=lambda t: t[0])) - benscabbia
1
在PyCharm中,无论我使用什么字典,我总是会收到这个警告: Unexpected type(s): (List[str]) Possible types: (Mapping) (Iterable[Tuple[Any, Any]]) - Euler_Salter

55

有许多Python模块提供字典实现,可以自动维护键的排序顺序。考虑使用纯Python且速度快如C语言实现的 sortedcontainers 模块。此外,还有一个性能比较,将其与其他流行选项进行了基准测试。

如果您需要不断添加和删除键/值对并进行迭代,则使用有序字典是不够的解决方案。

>>> from sortedcontainers import SortedDict
>>> d = {2:3, 1:89, 4:5, 3:0}
>>> s = SortedDict(d)
>>> s.items()
[(1, 89), (2, 3), (3, 0), (4, 5)]

SortedDict类型还支持基于索引的位置查找和删除,这是使用内置的dict类型无法实现的。

>>> s.iloc[-1]
4
>>> del s.iloc[2]
>>> s.keys()
SortedSet([1, 2, 4])

48

简单来说:

d = {2:3, 1:89, 4:5, 3:0}
sd = sorted(d.items())

for k,v in sd:
    print k, v

输出:

1 89
2 3
3 0
4 5

10
sd是一个元组列表,而不是字典。(但仍然很有用。) - nischi
我认为你的打印语句需要加上括号。print(k, v) - DenVog
你只需要在Python 3中使用()。在Python 2中,print k, v可以正常工作,因为print是一个关键字而不是函数。 - Alan Bagel

33

Python 3.6之前的Python字典是无序的。在Python 3.6的CPython实现中,字典保持插入顺序。从Python 3.7开始,这将成为一种语言特性。

在Python 3.6的变更日志中(https://docs.python.org/3.6/whatsnew/3.6.html#whatsnew36-compactdict):

这个新实现中保留顺序的方面被认为是一个实现细节,不应该依赖它(这可能会在未来改变,但希望在将语言规范强制要求保留顺序的语义之前,在语言中使用这个新的字典实现几个版本;这也有助于保持向后兼容性,以便与仍然存在随机迭代顺序的旧版本的语言(例如Python 3.5)兼容)。

在Python 3.7的文档中(https://docs.python.org/3.7/tutorial/datastructures.html#dictionaries):

在字典上执行list(d)会返回一个列表,其中包含字典中使用的所有键,按插入顺序排序(如果要进行排序,只需使用sorted(d)即可)。
因此,与以前的版本不同,在Python 3.6/3.7之后,您可以对字典进行排序。如果您想对包括子字典在内的嵌套字典进行排序,可以执行以下操作:
test_dict = {'a': 1, 'c': 3, 'b': {'b2': 2, 'b1': 1}}
    
def dict_reorder(item):
    return {k: dict_reorder(v) if isinstance(v, dict) else v for k, v in sorted(item.items())}
    
reordered_dict = dict_reorder(test_dict)

https://gist.github.com/ligyxy/f60f0374defc383aa098d44cfbd318eb


我喜欢这个,但是你的字典推导式中有一个 sort_dict(),可能应该改为 dict_reorder() - drs

29

找到另一种方法:

import json
print json.dumps(d, sort_keys = True)

更新:
1. 这个方法也可以对嵌套对象进行排序(感谢@DanielF)。
2. Python 字典是无序的,因此只适用于打印或分配字符串的情况。


但这也会对嵌套对象的键进行排序,这可能不是想要的。 - Daniel F
请注意,此代码仅适用于排序字典,不适用于列表(例如dict.keys()不能被排序因为它是一个列表)。 - Andrew

27

正如其他人所提到的,字典本质上是无序的。然而,如果问题只是要以有序的方式显示字典,您可以在字典子类中覆盖__str__方法,并使用这个字典类而不是内置的dict。例如:

class SortedDisplayDict(dict):
   def __str__(self):
       return "{" + ", ".join("%r: %r" % (key, self[key]) for key in sorted(self)) + "}"


>>> d = SortedDisplayDict({2:3, 1:89, 4:5, 3:0})
>>> d
{1: 89, 2: 3, 3: 0, 4: 5}

请注意,这不会改变键的存储方式,它们在迭代时返回的顺序等等,只是改变它们在print或Python控制台上的显示方式。


24

这里已经有很多答案展示了流行的Python字典排序方式。我想为那些从Google来到这里寻找非标准想法的人添加一些不太明显的方法。

示例字典:d = {2: 'c', 1: 'b', 0: 'a', 3: 'd'}

字典推导式

# Converts to list, sorts, re-converts to dict
{k: v for k, v in sorted(list(d.items()))}

使用Lambda表达式

排序并不总是按照严格的升序或降序排序。为了进行更有条件的排序,可以结合上述方法使用lambda表达式:

{k: v for k, v in sorted(d.items(), key=lambda v: ord(v[1]))}

更多示例

这个主题已经有足够多的好例子了。如果需要更多的示例,以及边缘情况和怪异情况,请查看此文章,了解如何在Python中对字典进行排序。


1
对于字典列表推导式,它对我不起作用,我需要将 sorted(list(d)) 替换为 sorted(d.items())(在 Python 3.8 上)。 - lhoupert
@ihoupert 不仅是你。我应该只复制/粘贴我的版本,而不是试图重新输入它。它肯定需要 .items() 调用。 - alphazwest
我遇到了类似的问题。我不得不使用.items(),感谢@ihoupert。 - Kofi

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