Python 3如何按照字典值对字典进行排序

91

我发现的方法只适用于Python2或仅返回元组列表。

是否可能按其值对字典进行排序,例如{"aa": 3, "bb": 4, "cc": 2, "dd": 1}

我想要实现的排序后的字典顺序是从大到小。 我希望结果如下所示:

bb 4
aa 3
cc 2
dd 1

排序后,我想将其存储到文本文件中。

6个回答

126

itemgetter (参见其他答案) 在处理大字典时更有效率,但对于常规情况下,我认为 d.get 更胜一筹。而且它不需要额外的 import

>>> d = {"aa": 3, "bb": 4, "cc": 2, "dd": 1}
>>> for k in sorted(d, key=d.get, reverse=True):
...     k, d[k]
...
('bb', 4)
('aa', 3)
('cc', 2)
('dd', 1)
请注意,你可以将d.__getitem__设置为key函数,这可能比d.get提供略微更好的性能提升。

1
请问您能否解释或扩展第二行的语法?我正在学习Python 3,希望能够理解这个。 - Serge
3
好的,但如果您告诉我不理解哪部分会更容易些。[x for x in iterable] 是Python中列表推导式(请使用谷歌搜索),这种方法在Python中创建列表时非常普遍和高效。(k, d[k])是一个由两个元素组成的元组,第二个元素(d[k])是字典中的值。sorted()是一个内置函数,返回按值排序的字典键。使用key=d.get是我的答案的关键,这一点并不是很容易知道。了解内置函数是必要的。希望这有所帮助。 - SzieberthAdam
谢谢!在入门课程中缺少的是“列表推导式”[x for x in iterable]。现在正在阅读有关它的内容(不知道名称很难找到)。 - Serge
我在最后一次编辑中使代码更简单,完全消除了列表推导式。 - SzieberthAdam

33
from collections import OrderedDict
from operator import itemgetter    

d = {"aa": 3, "bb": 4, "cc": 2, "dd": 1}
print(OrderedDict(sorted(d.items(), key = itemgetter(1), reverse = True)))

打印

OrderedDict([('bb', 4), ('aa', 3), ('cc', 2), ('dd', 1)])

尽管从你的最后一句话看来,元组列表似乎可以很好地工作,例如:

from operator import itemgetter  

d = {"aa": 3, "bb": 4, "cc": 2, "dd": 1}
for key, value in sorted(d.items(), key = itemgetter(1), reverse = True):
    print(key, value)

打印哪些内容

bb 4
aa 3
cc 2
dd 1

谢谢你的帮助。我认为其中一种解决方案会类似于这个。 - user2094432
1
dict keeps insertion order now, so there's no reason to use OrderedDict - user3064538
2
我能想到两个原因,首先它明确表明你关心顺序,其次有人可能在旧的解释器上运行你的代码,而默默地出现问题并不是一个好结果。 - plugwash

26

您可以使用字典推导式按照倒序(从大到小)排序:

{k: d[k] for k in sorted(d, key=d.get, reverse=True)}
# {'b': 4, 'a': 3, 'c': 2, 'd': 1}

如果你想按升序(从小到大)排序

{k: d[k] for k in sorted(d, key=d.get)}
# {'d': 1, 'c': 2, 'a': 3, 'b': 4}

如果您想按升序排序

{k: d[k] for k in sorted(d)}
# {'a': 3, 'b': 4, 'c': 2, 'd': 1}

这适用于CPython 3.6+和任何Python 3.7+的实现,因为字典保持插入顺序。


18

另一种方法是使用lambda表达式。根据解释器版本以及您想要创建排序字典还是排序键值元组(如OP所需),这甚至可能比接受的答案更快。

d = {'aa': 3, 'bb': 4, 'cc': 2, 'dd': 1}
s = sorted(d.items(), key=lambda x: x[1], reverse=True)

for k, v in s:
    print(k, v)

1
虽然你的代码可以运行,但我认为字典不能保证以添加的相同顺序返回项目。 - Ivan
2
@Ivan 谢谢 - 我已经删除了这里多余使用dict()的部分,尽管在CPython 3.6+中,dict是有序的,并且这很可能成为不久的将来的语言特性(https://docs.python.org/3/whatsnew/3.6.html)。 - Bede Constantinides
1
在所有以Python 3.7开始的版本中,dict会保留顺序。 - user3064538
你的计时不公平,因为对于你的方法,你(可能)计时返回一个 (key, value) 元组列表。如果你同时计时两种方法返回字典:%timeit {k: d[k] for k in sorted(d, key=d.get, reverse=True)}%timeit dict(sorted(d.items(), key=lambda x: x[1], reverse=True)),那么你的方法会慢10%。 - user3064538
1
实际上它少于10%,我在具有100,000个元素的字典上使用Python 3.8.6时获得了54毫秒与57.3毫秒相比,但仍然从技术上来说较慢。我认为你应该将它们删除,这不是一种值得优化的方式。 - user3064538
显示剩余3条评论

10

要对字典进行排序,我们可以利用 operator 模块。这里是 operator 模块的文档 链接

import operator                             #Importing operator module
dc =  {"aa": 3, "bb": 4, "cc": 2, "dd": 1}  #Dictionary to be sorted

dc_sort = sorted(dc.items(),key = operator.itemgetter(1),reverse = True)
print dc_sort

输出序列将是一个已排序的列表:

[('bb', 4), ('aa', 3), ('cc', 2), ('dd', 1)]

如果我们想按键进行排序,可以利用

dc_sort = sorted(dc.items(),key = operator.itemgetter(0),reverse = True)

输出序列将为:

[('dd', 1), ('cc', 2), ('bb', 4), ('aa', 3)]

Paul Draper的答案已经在使用操作符...只是没有导入完整的库。 - Salvatore Cosentino

0

如果你想对一个字典进行排序并且之后仍然保持其字典的特性,你可以使用标准库中的OrderedDict

如果这不是你所需要的,我鼓励你重新考虑那些会让你得到一个元组列表的排序函数。如果不是有序的键值对列表,你希望得到什么输出呢?


dict keeps insertion order now, so there's no reason to use OrderedDict - user3064538

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