题 如何按值对字典进行排序?


我有一个从数据库中的两个字段读取的值字典:字符串字段和数字字段。字符串字段是唯一的,因此这是字典的关键字。

我可以对键进行排序,但是如何根据值进行排序?

注意:我已阅读Stack Overflow问题 如何按Python中字典的值对字典列表进行排序? 并且可能会改变我的代码以获得字典列表,但由于我不需要字典列表,我想知道是否有更简单的解决方案。


2938
2018-03-05 00:49


起源


字典数据结构没有固有的顺序。您可以迭代它,但没有什么可以保证迭代将遵循任何特定的顺序。这是设计的,所以你最好的选择是使用anohter数据结构进行表示。 - Daishiman
“sorted()”可以对字典进行操作(并返回已排序键的列表),所以我认为他已经意识到了这一点。在不知道他的程序的情况下,告诉别人他们使用错误的数据结构是荒谬的。如果90%的时间都需要快速查找,那么dict可能就是你想要的。 - bobpaul
对于那些暗示这是重复的人 stackoverflow.com/questions/72899/... ,该问题被标记为此问题的副本。 - Marcin
如果可能,请实例化NumPy Series 从字典中排序并使用它 pandas.Series.order - Dror
这里以清晰简洁的方式介绍了排序词典的所有三个输出(键,值,两者): stackoverflow.com/questions/16772071/sort-dict-by-value-python - JStrahl


答案:


不可能对字典进行排序,只是为了获得已排序的字典的表示。字典本质上是无序的,但其他类型(如列表和元组)则不是。因此,您需要一个有序数据类型来表示排序值,这将是一个列表 - 可能是元组列表。

例如,

import operator
x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = sorted(x.items(), key=operator.itemgetter(1))

sorted_x 将是由每个元组中的第二个元素排序的元组列表。 dict(sorted_x) == x

对于那些希望按键而不是值进行排序的人:

import operator
x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = sorted(x.items(), key=operator.itemgetter(0))

在Python3中,因为不允许解压缩 [1] 我们可以用

x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_by_value = sorted(x.items(), key=lambda kv: kv[1])

3555
2018-03-05 00:59



按价值计划排序各种字典的时间: writeonly.wordpress.com/2008/08/30/... - Gregg Lind
sorted_x.reverse() 会给你一个降序(由第二个元组元素) - saidimu apale
saidimu:因为我们已经在使用了 sorted()传递它的效率要高得多 reverse=True 论据。 - rmh
在python3中我使用了lambda: sorted(d.items(), key=lambda x: x[1])。这将在python 2.x中工作吗? - Keyo
OrderedDict在2.7中添加到集合中。排序示例显示在: docs.python.org/library/... - monkut


很简单: sorted(dict1, key=dict1.get)

嗯,实际上可以做一个“按字典值排序”。最近我不得不在Code Golf(Stack Overflow问题)中这样做 Code golf:Word频率图)。简而言之,问题就是这样:给定一个文本,计算每个单词遇到的频率,并显示顶部单词列表,按频率降低排序。

如果构造一个字典,其中单词为键,每个单词的出现次数为值,则简化为:

from collections import defaultdict
d = defaultdict(int)
for w in text.split():
  d[w] += 1

然后你可以得到一个单词列表,按照使用频率排序 sorted(d, key=d.get)  - 排序迭代字典键,使用单词出现次数作为排序键。

for w in sorted(d, key=d.get, reverse=True):
  print w, d[w]

我正在写这个详细的解释,以说明人们通常所说的“我可以轻松地按键排序字典,但我如何按价值排序” - 我认为OP试图解决这个问题。解决方案是根据值对键进行排序,如上所示。


969
2017-07-05 08:01



这也很好但是 key=operator.itemgetter(1) 应该比效率更具可扩展性 key=d.get - smci
您首先需要:import collections#以使用defaultdict - rjurney
@raylu我确实使用itemgetter观察到“不起作用”的行为:----- from operator import itemgetter d = {"a":7, "b":1, "c":5, "d":3} sorted_keys = sorted(d, key=itemgetter, reverse=True) for key in sorted_keys: print "%s: %d" % (key, d[key])  ----- - > b:1 c:5 a:7 d:3每次运行代码时结果都会改变:很奇怪。 (抱歉,无法正常显示代码) - bli
@bli sorted_keys = sorted(d.items(), key=itemgetter(1), reverse=True) 和 for key, val in sorted_keys: print "%s: %d" % (key, val)  - itemgetter在调用时创建一个函数,你不要像在你的例子中那样直接使用它。并且dict上的普通迭代使用没有值的键 - Izkata
我是从未来来告诉你的 collections.Counter,有一个 most_common 你可能感兴趣的方法:) - Eevee


你可以使用:

sorted(d.items(), key=lambda x: x[1])

这将根据字典中从最小到最大的每个条目的值对字典进行排序。


607
2018-02-13 16:33



+1成为最干净的解决方案。但是它不对字典进行排序(哈希表,不可能),而是返回有序列表 (key, value) 元组。 - Keyo
@Keyo我是python的新手,并且遇到了对字典进行排序的需要。而且我想确保我理解你:没有办法使用lambda来排序字典,对吧? - lv10
我更喜欢 key=lambda (k, v): v 亲自 - Claudiu
@Claudiu我喜欢那个 (k, v) 语法也是如此,但它在Python 3中不可用 元组参数解包 去掉了。 - Bob Stein
@Nyxynyx只需添加 reverse=True 在排序位内(即 sorted(a.items(), key=lambda x: x[1], reverse=True)) - Mathime


Dicts无法排序,但您可以从中构建排序列表。

dict值的排序列表:

sorted(d.values())

按键排序的(键,值)对列表:

from operator import itemgetter
sorted(d.items(), key=itemgetter(1))

165
2018-03-05 01:05



+1:排序(d.values())比Nas的排序(dict1,key = dict1.get)更容易阅读/理解,因此更多Pythonic。关于可读性,请也考虑我的 namedtuple 建议。 - Remi
具有相同值的键的顺序是什么?我先按键排序列表,然后按值排序,但不保留具有相同值的键的顺序。 - SabreWolfy
@Remi,那是两件不同的事! sorted(d.values()) 返回的排序列表 值 来自字典,在哪里 sorted(d, key=d.get) 返回的列表 按键,按值排序!方式不同。如果您没有看到后者的需要,请阅读上面的帖子,了解“真实生活”的例子 - Nas Banov


在最近的Python 2.7中,我们有了新的 OrderedDict type,记住添加项目的顺序。

>>> d = {"third": 3, "first": 1, "fourth": 4, "second": 2}

>>> for k, v in d.items():
...     print "%s: %s" % (k, v)
...
second: 2
fourth: 4
third: 3
first: 1

>>> d
{'second': 2, 'fourth': 4, 'third': 3, 'first': 1}

要从原始字典创建新的有序字典,请按值排序:

>>> from collections import OrderedDict
>>> d_sorted_by_value = OrderedDict(sorted(d.items(), key=lambda x: x[1]))

OrderedDict的行为类似于普通的dict:

>>> for k, v in d_sorted_by_value.items():
...     print "%s: %s" % (k, v)
...
first: 1
second: 2
third: 3
fourth: 4

>>> d_sorted_by_value
OrderedDict([('first': 1), ('second': 2), ('third': 3), ('fourth': 4)])

128
2017-07-05 02:50



这不是问题所在 - 它不是关于维护键的顺序而是关于“按值排序” - Nas Banov
@Nas Banov:它不是按键排序。它按顺序排序,我们创建项目。在我们的例子中,我们按值排序。不幸的是,不幸的是,选择了3项dict,因此顺序是相同的,当按值和键排序时,所以我扩展了样本字典。 - mykhal
sorted(d.items(), key=lambda x: x[1]) 你能解释一下吗? x 意思是,为什么它可以采取 x[1] 到lambda?为什么不能 x[0]?非常感谢你! - JZAU
@jie d.items() 返回字典中的键/值对列表 x 是这个元组的一个元素。 x[0] 将是关键和 x[1] 将是价值。当我们打算对价值进行排序时,我们会通过 x[1] 到了lambda。 - CadentOrange
@Boern d.items() 返回类似列表的容器 (key, value)元组。 [0] 访问元组的第一个元素 - 键 - 和 [1] 访问第二个元素 - 值。 - BallpointBen


更新:2015年12月5日使用Python 3.5

虽然我发现接受的答案很有用,但我也很惊讶它没有更新以供参考 OrderedDict 来自标准库 集合 模块作为一种可行的,现代的替代方案 - 旨在解决这类问题。

from operator import itemgetter
from collections import OrderedDict

x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
sorted_x = OrderedDict(sorted(x.items(), key=itemgetter(1)))
# OrderedDict([(0, 0), (2, 1), (1, 2), (4, 3), (3, 4)])

官方 OrderedDict 文档也提供了一个非常相似的例子,但是使用lambda作为sort函数:

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

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

75
2017-12-05 09:46





它通常非常方便使用 namedtuple。例如,您有一个'name'字典作为键,'score'作为值,您想要对'score'进行排序:

import collections
Player = collections.namedtuple('Player', 'score name')
d = {'John':5, 'Alex':10, 'Richard': 7}

首先排序得分最低:

worst = sorted(Player(v,k) for (k,v) in d.items())

首先排序得分最高:

best = sorted([Player(v,k) for (k,v) in d.items()], reverse=True)

现在你可以得到名字和得分,让我们说第二好的球员(指数= 1)非常像这样:

player = best[1]
player.name
    'Richard'
player.score
    7

64
2017-08-30 00:30



我怎么能把它转换成字典? - rowana
as_list = [Player(v,k)for(k,v)in d.items()] as_dict = dict((p.name,p.score)for p in as_list) - Remi


与Hank Gay的回答几乎相同;


    排序(mydict.items()中(键,值)的[(值,键)])

或者根据John Fouhy的建议进行优化;


    mydict.items()中的(键,值)的排序((值,键))


57
2018-03-05 01:06



..和Hank Gay的答案一样,你不需要方括号。 sorted()将很乐意接受任何迭代,例如生成器表达式。 - John Fouhy
您可能仍需要交换(value,key)元组元素以(key,value)结束。然后需要另一个列表理解。 [(key, value) for (value, key) in sorted_list_of_tuples] - saidimu apale
不,最好留下方括号,因为 sorted 无论如何都必须重建列表,从gencomp重建会更快。有利于编码,对速度不利。保持丑陋 ([]) 版。 - Jean-François Fabre


作为 Python 3.6 将订购内置字典

好消息,所以OP的原始用例是从具有唯一字符串ID的数据库中检索到的映射对作为键和数值作为值到内置Python v3.6 + dict,现在应该遵循插入顺序。

如果说从数据库查询得到的两个列表表达式如下:

SELECT a_key, a_value FROM a_table ORDER BY a_value;

将存储在两个Python元组中,k_seq和v_seq(由数字索引对齐,当然长度相同),然后:

k_seq = ('foo', 'bar', 'baz')
v_seq = (0, 1, 42)
ordered_map = dict(zip(k_seq, v_seq))

允许稍后输出为:

for k, v in ordered_map.items():
    print(k, v)

在这种情况下产生(对于新的Python 3.6+内置字典!):

foo 0
bar 1
baz 42

每个v值相同的排序。

在我的机器上安装Python 3.5的地方,它目前产生:

bar 1
foo 0
baz 42

细节:

正如Raymond Hettinger在2012年提出的那样(参见python-dev上的邮件主题 “更快速迭代的更紧凑的词典”)现在(2016年)由Victor Stinner在邮件中宣布主题为python-dev “Python 3.6 dict变得紧凑并获得私有版本;关键字变得有序” 由于问题27350的修复/实施 “紧凑和有序的字典” 在Python 3.6中我们现在可以使用内置的dict来维护插入顺序!

希望这将导致薄层OrderedDict实现作为第一步。正如@ JimFasarakis-Hilliard所指出的那样,有些人在未来也会看到OrderedDict类型的用例。我认为整个Python社区将仔细检查,如果这将经得起时间的考验,以及接下来的步骤将是什么。

是时候重新考虑我们的编码习惯,不要错过稳定订购的可能性:

  • 关键字参数和
  • (中间)dict存储

第一个是因为它在某些情况下简化了函数和方法实现中的调度。

第二,因为它鼓励更容易使用 dict作为处理管道的中间存储。

Raymond Hettinger友好地提供了解释“Python 3.6词典背后的技术“ - 来自旧金山Python Meetup Group 2016-DEC-08的演讲。

也许相当一些Stack Overflow高度装饰的问答页面将收到此信息的变体,许多高质量的答案也需要每个版本更新。

警告Empat(但也见下面更新2017-12-15):

正如@ajcr正确地指出:“这个新实现的顺序保留方面被认为是一个实现细节,不应该依赖它。” (来自 whatsnew36)不挑剔,  引文被削减了一点悲观;-)。它继续作为“(这可能在未来发生变化,但是在更改语言规范之前,希望在几种版本的语言中使用这个新的dict实现,以便为所有当前和未来的Python实现强制保持语义保持语义;这也是有助于保持与随机迭代顺序仍然有效的语言的旧版本的向后兼容性,例如Python 3.5)。“

因此,在某些人类语言(例如德语)中,用法形成了语言,现在已经声明了... whatsnew36

更新2017-12-15:

在一个 邮件到python-dev列表,Guido van Rossum宣称:

这样做。 “Dict保持插入秩序”是裁决。谢谢!

因此,dict插入排序的版本3.6 CPython副作用现在正成为语言规范的一部分(而不再仅仅是实现细节)。邮件线程也出现了一些与众不同的设计目标 collections.OrderedDict 正如Raymond Hettinger在讨论中提醒的那样。


48
2017-09-10 10:05



应强调您链接到的“whatsnew”页面上的警告: 这个新实现的顺序保留方面被认为是一个实现细节,不应该依赖它。没有人应该假设 dict type将尊重其代码中的插入顺序。这不是语言定义的一部分,实现可能会在将来的任何版本中发生变化。继续使用 OrderedDict 保证订单。 - Alex Riley
@ajcr感谢您的警告,非常感谢 - 因为笑脸和可能已经编织到我的回答中,这些应该表明,变化是巨大的,但当然,只适用于CPython(参考实现)和PyPy。对于完全不同的东西......在编写人机指令时,我很少谈及非实现细节。如果它只是Jython ;-) ......我可能没有勇气写出来。 - Dilettant
OrderedDict 绝对不会被丢弃;相反,它将成为当前dict实现的一个薄包装器(所以你可以补充说它也会变得更紧凑)。添加该片段 ImportError 因为误导读者而不是最好的主意 OrderedDict 没用 - Jim Fasarakis Hilliard
@ JimFasarakis-Hilliard感谢您的反馈。 “相当好的想法”让我微笑 - 未来通常很难预测。但我喜欢你的建议会检查来源,尝试然后相应地更新答案。再次感谢。 - Dilettant
在回答这个答案和结构化的决定时,我发布了 一个新的答案。欢迎反馈! - Bram Vanroy


鉴于字典

e = {1:39, 4:34, 7:110, 2:87}

排序

sred = sorted(e.items(), key=lambda value: value[1])

结果

[(4, 34), (1, 39), (2, 87), (7, 110)]

在这种情况下,您可以使用lambda函数按值对事物进行排序,并将它们存储在变量中 SRED 同 Ë 原始字典。

希望有所帮助!


41
2018-01-25 14:54