如何在 Python 中按键对字典进行排序
Posted
技术标签:
【中文标题】如何在 Python 中按键对字典进行排序【英文标题】:How to sort dictionaries by keys in Python 【发布时间】:2011-06-06 06:19:23 【问题描述】:谁能告诉我如何排序:
'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,代码示例:
所以我在做语言学。一篇文章被分解为存储在数据库中的单词,并具有各种属性,包括 para ID 和 sentence ID。任务:尝试重建原始文本。
从 DB 中获取 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]=[]
然而,在这一点上,如果我尝试循环 dict 并重建文本,一些后面的 id'd 段落会出现在前面的段落之前,这就是不行。
更新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 %
【问题讨论】:
...为什么,确切地说,你想要这个吗? 我猜现在的代码说明了我为什么要这样做 "如果我尝试循环 dict 并尝试重建文本,一些后面的 id-d 段落会出现在前面的段落之前,并且不会这样做。"是的。所以使用sorted()
。真的,就这么简单。
我认为:paras=sorted(paras) 在我看来,但发生的情况是我丢失了单词字典的数据结构。 word['type']='verb', word['special']='true' 我得到错误:“'list' object has no attribute 'keys'”
不,你没有得到一个“松散的结构”,你从字典中得到一个排序的键/值元组列表,然后你可以循环。你应该合理地(根据我的例子)在循环中使用sorted()
; for k,v in sorted(paras):
或类似的。此外,您完全跳过了代码的相关部分,即循环。
【参考方案1】:
字典没有顺序。
你可以调用 sorted 但这只是给你一个排序的键列表:
>>> sorted(d)
['a', 'b', 'c', 'd']
您可以将其视为一个可迭代对象并对键值元组进行排序,但是您只是得到了一个元组列表。这和 dict 不一样。
>>> sorted(d.items())
[
('a', [1, 2, 3]),
('b', ['blah', 'bhasdf', 'asdf']),
('c', ['one', 'two']),
('d', ['asdf', 'wer', 'asdf', 'zxcv'])
]
如果您使用的是 Python 2.7 或更新版本,您也可以考虑使用OrderedDict
。
添加了记住订单条目的dict子类
例如:
>>> d = collections.OrderedDict(sorted(d.items()))
>>> for k, v in d.items():
>>> print k, v
一个 [1, 2, 3]
b ['废话','bhasdf','asdf']
c ['一个','两个']
d ['asdf', 'wer', 'asdf', 'zxcv']
【讨论】:
好吧,但这对我帮助不大,是吗?也许没有内置函数,但有更复杂的用户编写的解决方案? 答案的原始版本中没有提到 OrderedDict。 @mgPePe 对我来说似乎是一个合适的答案,对你来说也是一个合理的解决方案 - 如果不是,你能提供更多关于你想要做什么的细节吗? 已排序!=已排序。如果他希望项目排序,他应该使用 sorted() 函数对键进行排序。如果他想让它们有序,他应该使用 OrderedDict。 @Matt - 我正在尝试获取已排序的字典。 OrderedDict 听起来是正确的,但它后来被添加到较新版本的 python 中,并且在 2.6 中不起作用。我收到“ImportError:无法导入名称 OrderedDict”。我想要得到的是另一个有序字典,而不是项目列表。只是为了确保我明白了:问题是python中的常规字典根本没有排序概念,而不是它没有预建的函数来排序,这就是你所说的“字典不”没有订单。您无法对它们进行排序。”?【参考方案2】:正确的答案是,如果您希望字典中的项目按排序顺序排列,则应该在遍历字典时使用 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 是 ordered 而不是 sorted。
考虑一个标准字典:
>>> 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)]
但这与标准字典一样有效,因此 OrderedDictionary 没有帮助:
>>> 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 并不能真正帮助您,因为它不关心 排序,只关心您添加内容的 order。
【讨论】:
+ 1 既然你正确解释了这个问题,我会马上删除我的(错误的)答案(或者为了完整起见,我明天会删除它);-) 嗯,但是当您尝试构建新的 Dict 时会出现问题。让我们来看看你的第一个循环。它确实可以正确打印以下内容:a:1、b:2、c:3 等等。但是,当您尝试用 new_dict[k]=v 替换打印行,然后在解释器中打印 v 时,您会得到另一个未排序的字典 a:1, c:3, b:2 @mgPePe:“新字典”? “其他”?字典未排序。遍历它们时需要使用 sorted() 。总是。 @lennart:我是一个新手,我很难实现这一点。原因如下:我有一篇文章。它分为段落,句子,单词。我正在分析语言学。每个单词都有它的 para ID、sentence ID 和一堆属性。我想通过将单词连接在一起来重建原始文本。我提取了 500 个按 ID 排序的单词并将它们存储在一个字典中,但是在我做了几次操作之后,这些单词不再排序,我试图重建的文本是一团糟。 @mgPepe:是的,因此您必须在字典准备好重建时对其进行排序。你使用sorted()
来做到这一点。重建时循环遍历字典,对吗?只需在该循环中围绕它们粘贴一个 sorted() 即可。如果这不起作用,请发布代码的相关位。 除非您实际上不想对其进行排序,否则您希望对其进行排序,即取出它们时的顺序与放入时的顺序相同。然后您可以从一开始就使用 OrderedDict 而不是一个标准的字典。【参考方案3】:
值得注意的是,Python 有许多字典实现,它们按排序顺序维护键。考虑 sortedcontainers 模块,它是纯 Python 和 fast-as-C 实现。有一个 performance comparison 与其他快速且功能完整的实现相互进行了基准测试。
例如:
>>> 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 完全替换您对 dict 的使用,因为它支持快速获取/设置操作和按键的排序迭代。
【讨论】:
【参考方案4】:这是一个快速简便的功能,可用于按键对字典进行排序。
将此代码放在名为sdict.py
的单独文件中:
def sortdict(dct):
kys = dct.keys()
kys.sort()
from collections import OrderedDict
d = OrderedDict()
for x in kys:
for k, v in dct.iteritems():
if (k == x):
d[k] = v
return d
现在,将此代码放入名为 test.py
的单独文件中,以使用示例字典对其进行测试:
from sdict import sortdict
import json
dct = 'sizes':[32,28,42], 'dog':'schnauser', 'cat':'siamese', 'bird':'falcon'
dctx = sortdict(dct)
print json.dumps(dctx)
最后,从命令行调用test.py
:
$ python test.py
"bird": "falcon", "cat": "siamese", "dog": "schnauser", "sizes": [32, 28, 42]
我只是使用 json.dumps 行来向您展示它是一个实际的字典,而不仅仅是一个字符串表示。你也可以使用 type() 函数来测试它。
我在示例字典中包含了一个带有数值的嵌套列表,以表明该函数可以处理更复杂的字典,而不仅仅是基于字符串的单层字典。
代码非常简单,因此可以很容易地修改它以按值排序,如果这是您的偏好 - 尽管如果某些值是对象,如列表、元组或其他字典,按值排序将没有意义.
诚然,这只适用于 python 2.7 或更高版本。
干杯, -=卡梅隆
【讨论】:
【参考方案5】:正如另一个答案提到的,字典键的顺序是任意的,你不应该依赖它。
如果您使用的是 Python 2.7 或 3.1 或更高版本,请试用collections.OrderedDict
(2.7 docs;3.1 docs;另请参阅PEP 372)。文档中有一个指向 pure-Python version of OrderedDict 的链接,该链接适用于早期的 Python 版本。
【讨论】:
【参考方案6】:还值得一提的是 heapq 中的 nlargest 例程。这将排序并返回前 N 个项目。根据实际需要,如果您使用 key 参数,这可能会很方便。我主要提到这一点,因为我几天前发现了它,它完全符合我的要求。见PEP 0265 和Heapq。
【讨论】:
【参考方案7】:我会在其他人已经解释过的内容上加一分钱。在一个特定情况下,我碰巧遇到了完全相同的问题。为了编写稳定的单元测试,我需要字典的输出始终相同。
如果碰巧这是您想要实现的目标,或者其他与输出相关的任务,您根本不需要对任何内容进行排序,只需使用 pprint
模块,它会按键对字典进行排序。
>>> d = 'a':1, 'b':2, 'c':3
>>> print d
'a': 1, 'c': 3, 'b': 2
>>> from pprint import pprint
>>> pprint(d)
'a': 1, 'b': 2, 'c': 3
【讨论】:
thanx @kriss,我在 SO 上阅读了另一个关于它的问题,但 print 本身并不是我需要的,而且我认为它不会在所有版本的 python 中排序以上是关于如何在 Python 中按键对字典进行排序的主要内容,如果未能解决你的问题,请参考以下文章
Python对字典分别按键(key)和值(value)进行排序
如何使用 Pandas 在 Python 中对字典中的数据进行排序