我有一本按照特定顺序声明的字典,并希望一直保持该顺序。键/值不能真正根据它们的值来保持顺序,我只想按声明的顺序来保存。

所以如果我有字典:

d = {'ac': 33, 'gw': 20, 'ap': 102, 'za': 321, 'bs': 10}


如果我查看或遍历它的顺序不是这样,是否有任何方法可以确保Python保持我声明键/值的显式顺序? br />

#1 楼

从Python 3.6开始,标准的dict类型默认情况下会保持插入顺序。
定义
d = {'ac':33, 'gw':20, 'ap':102, 'za':321, 'bs':10}

将生成字典,其中的键按源代码中列出的顺序排列。
这是通过将一个带有整数的简单数组用于稀疏哈希表来实现的,其中,这些整数索引到另一个存储键值对(加上计算得出的哈希)的数组中。后面那个数组恰好按插入顺序存储项目,实际上,整个组合使用的内存少于Python 3.5及之前版本中使用的实现。有关详细信息,请参见Raymond Hettinger最初的想法。
在3.6中,这仍然被视为实现细节;请参阅Python 3.6的新增功能:

此新实现的顺序保留方面被视为实现细节,因此不应依赖(将来可能会改变,但是希望在更改语言规范以强制所有当前和将来的Python实现强制保留顺序的语义之前,先在该语言中使用该新的dict实现几个版本;这还有助于保持与该语言的旧版本(仍然具有随机迭代顺序)的向后兼容性实际上,例如Python 3.5)。

Python 3.7将此实现细节提升为一种语言规范,因此现在必须dict保留与该版本或更高版本兼容的所有Python实现中的顺序。参见BDFL的声明。从Python 3.8开始,字典还支持反向迭代。
在某些情况下,您仍可能希望使用collections.OrderedDict()类,因为它在标准dict类型的基础上提供了一些附加功能。例如是可逆的(这扩展到视图对象),并支持重新排序(通过q​​4312079q方法)。

#2 楼

from collections import OrderedDict
OrderedDict((word, True) for word in words)


包含

OrderedDict([('He', True), ('will', True), ('be', True), ('the', True), ('winner', True)])


如果值是True(或任何其他不可变的对象),则还可以使用:

OrderedDict.fromkeys(words, True)


评论


当然,值得注意的是,“不可变”部分并不是Python将要执行的一成不变的规则-它的“唯一”是个好主意。

–lvc
2012年6月11日14:37

请注意,当提到一个方法时,诸如:OrderedDict(FUTURE = [],TODAY = [],PAST = [])之类的解决方案将不起作用:OrderedDict([('FUTURE',[]),('TODAY',[ ])(('PAST',[])])将保持秩序。

– andilabs
2014年6月5日在13:47

@andi我遇到另一个问题,当使用jsonify时,在生成json数据时,OrderedDict似乎丢失了顺序。是否可以解决此问题?

–user4985526
16年3月31日在2:57

github.com/pallets/flask/issues/974这可以用来解决问题。

–user4985526
16年3月31日在3:01

Python3.7现在默认情况下已将dict排序。 mail.python.org/pipermail/python-dev/2017-December/151283.html

–sertsedat
'18 Sep 4'在8:05

#3 楼

我不会解释理论部分,而是给出一个简单的示例。

>>> from collections import OrderedDict
>>> my_dictionary=OrderedDict()
>>> my_dictionary['foo']=3
>>> my_dictionary['aol']=1
>>> my_dictionary
OrderedDict([('foo', 3), ('aol', 1)])
>>> dict(my_dictionary)
{'foo': 3, 'aol': 1}


评论


有没有办法像Dict类型那样批量分配OrderedDict?

–user4985526
16年3月31日在2:50

OrderedDict确实解决了问题,但是...在此特定示例中,使用标准字典可获得完全相同的结果

–Tonechas
16-4-25在19:08



@Tonechas:我只是用标准字典尝试了该示例,并得到了{'aol':1,'foo':3},所以我认为这是一个很好的说明性示例。

–特斯布里利格
16年5月3日在20:13



每个人都有一个教训:发现(我认为是在2.4版本附近),Python的可预测哈希可能会引起安全漏洞,因此现在无法保证即使是同一代码的两次不同运行也将在标准中给出相同的顺序字典

– holdenweb
16 Sep 1'在8:19



@tyan可以使用包含键值对的可迭代对象调用OrderedDict.update():d1.upate([((key1,val1),(key2,val2)])。

– Ruud Althuizen
18/09/12在11:06



#4 楼

请注意,此答案适用于python3.7之前的python版本。 CPython 3.6在大多数情况下都将插入顺序作为实现细节来维护。从Python3.7开始,已经声明实现必须保持插入顺序符合要求。


python字典是无序的。如果需要有序字典,请尝试collections.OrderedDict。

请注意,OrderedDict是python 2.7中的标准库中引入的。如果您使用的是python的旧版本,则可以在ActiveState上找到有序词典的食谱。

评论


参见上面的@martijn的帖子。从python 3.6开始,dict支持插入顺序。

–tpk
17年7月17日在10:28



#5 楼

字典将使用使搜索有效的顺序,您不能更改它,

您可以只使用对象列表(在简单情况下为2个元素元组,甚至是一个类),然后追加项目到最后。然后,您可以使用线性搜索在其中查找项目。

或者,您可以创建或使用为维护顺序而创建的其他数据结构。

评论


字典将使用使搜索有效的顺序。最后,有人指出了这一点。

– scharette
18年11月27日,0:20

#6 楼

我在尝试弄清楚如何使OrderedDict工作时碰到了这篇文章。用于Eclipse的PyDev根本找不到OrderedDict,所以我最终决定按我希望对字典的键值进行排序的元组。当我需要输出列表时,我只需遍历元组的值,然后将元组中迭代的“键”插入字典中,即可按需要的顺序检索值。

示例:

test_dict = dict( val1 = "hi", val2 = "bye", val3 = "huh?", val4 = "what....")
test_tuple = ( 'val1', 'val2', 'val3', 'val4')
for key in test_tuple: print(test_dict[key])


有点麻烦,但我时间紧迫,这是我想出的解决方法。

注意:别人建议的列表方法对我来说真的没有意义,因为列表是有序的和索引的(并且结构与字典不同)。

评论


很好的解决方案。我将使用它来将json写入文件,总是以相同的顺序进行。

–Hrvoje T
18年4月27日在21:53

#7 楼

您真的无法用字典来完成所需的工作。您已经具有创建的字典d = {'ac':33, 'gw':20, 'ap':102, 'za':321, 'bs':10}。我发现一旦创建就无法保持秩序。我所做的是用对象代替json文件:

{"ac":33,"gw":20,"ap":102,"za":321,"bs":10}


我用过:

r = json.load(open('file.json'), object_pairs_hook=OrderedDict)


然后使用:

print json.dumps(r)


进行验证。

评论


那么,为什么不从列表中的OrderedDict开始呢? JSON文件实际上并未在此处添加任何内容。

–马丁·彼得斯(Martijn Pieters)♦
17年6月13日在6:21

是的,列表对于保持秩序更有用,但是答案是关于字典排序的问题。只是让人们知道使用字典的局限性,如果他们出于某种原因需要使用字典,可以给他们一个可能的解决方法。

–nealous3
17年6月14日在10:33

#8 楼

from collections import OrderedDict
list1 = ['k1', 'k2']
list2 = ['v1', 'v2']
new_ordered_dict = OrderedDict(zip(list1, list2))
print new_ordered_dict
# OrderedDict([('k1', 'v1'), ('k2', 'v2')])


评论


主要问题不再是字典,而是元组列表

–奥列格(Oleg)
5月22日22:06



#9 楼

另一种选择是使用Pandas dataframe,因为它可以保证像dict一样的结构的顺序和索引位置。

#10 楼

通常,您可以设计行为类似于字典的类,主要是实现方法__contains____getitem____delitem____setitem__等。该类可以具有您喜欢的任何行为,例如,对键使用排序的迭代器...

#11 楼

如果您希望按特定顺序拥有字典,则还可以创建一个列表列表,其中第一项是键,第二项是值
,看起来像这样
示例

>>> list =[[1,2],[2,3]]
>>> for i in list:
...     print i[0]
...     print i[1]

1
2
2
3


评论


那不是“字典”,因为如果不搜索整个集合(花费O(n)时间),就无法通过项的键来查找项。

– BHSPitMonkey
2014年5月1日,0:09

是的,它不是字典,但是根据情况,它可以为原始海报提供有效的解决方案。

– SunSparc
15年8月25日在21:21

#12 楼

开发Django项目时遇到类似的问题。我无法使用OrderedDict,因为我正在运行旧版本的python,因此解决方案是使用Django的SortedDict类:

https://code.djangoproject.com/wiki/SortedDict

,例如,

from django.utils.datastructures import SortedDict
d2 = SortedDict()
d2['b'] = 1
d2['a'] = 2
d2['c'] = 3


注意:此答案最初来自2011年。如果您可以使用Python 2.7或更高版本,则应该可以使用到现在的标准collections.OrderedDict,该线程中的其他示例提供了许多示例。

#13 楼

您可以执行与字典相同的操作。

创建列表并清空字典:

dictionary_items = {}
fields = [['Name', 'Himanshu Kanojiya'], ['email id', 'hima@gmail.com']]
l = fields[0][0]
m = fields[0][1]
n = fields[1][0]
q = fields[1][1]
dictionary_items[l] = m
dictionary_items[n] = q
print dictionary_items