Python 在字典上迭代将按排序顺序返回键
我有一个关于python如何处理字典中的数据的问题。假设我有一个简单的字典,其中数字作为键,数字作为值,如下所示:Python 在字典上迭代将按排序顺序返回键,python,dictionary,Python,Dictionary,我有一个关于python如何处理字典中的数据的问题。假设我有一个简单的字典,其中数字作为键,数字作为值,如下所示: a = { 5: 3, 20: 1, 1: 1, 5: 2, 100: 3, 11: 6, 14: 1, 15: 2, 16: 4, 17: 2, 25: 1, 19: 1 } 我想反复阅读这本字典并打印出键。每次我循环浏览字典(如下所示),它都会按递增顺序打印键 这就是我想要它做的,但我想知道,就我自己所知,为什么会发生这种情况?它是否每次都按递增顺序自动排序?正如您
a = { 5: 3, 20: 1, 1: 1, 5: 2, 100: 3, 11: 6,
14: 1, 15: 2, 16: 4, 17: 2, 25: 1, 19: 1 }
我想反复阅读这本字典并打印出键。每次我循环浏览字典(如下所示),它都会按递增顺序打印键
这就是我想要它做的,但我想知道,就我自己所知,为什么会发生这种情况?它是否每次都按递增顺序自动排序?正如您在上面的字典中所看到的,这些键显然不是按递增顺序排列的,但下面的输出是按递增顺序打印的
我只是想获得一个清晰的理解,任何帮助都将不胜感激。谢谢
例子
输出:
报告说:
最好将字典视为一组无序的键:值
配对,要求密钥是唯一的
与Python列表或元组不同,dict对象中的键和值对没有任何特定顺序。尽管在实例化字典时,键值对是按特定顺序存储的,但只要调用dict,就可以看到它们的存储顺序不同。
然后,如果要对它们进行排序,只需使用内置方法,字典中的整数并不总是按键排序:
a = {2:0, 9:0}
print a.keys() # [9, 2]
Python字典是一种特殊类型的数组,其中存储值的单元格的索引是通过对键应用特殊函数(我们称之为hash
函数)派生的。
这样,如果要检索特定键的值,可以再次计算该键的散列
函数,该函数将返回与以前相同的结果,从而获得存储该值的索引
hash
函数将数据类型转换为整数:
print hash(1) # 1
print hash('hello') # 840651671246116861
print hash((2,3)) # 3713082714463740756
每种类型都可以定义自己的散列计算方法,int
通常返回自身:
print hash(1) # 1
print hash(20) # 20
print hash(1000) # 1000
正如您所看到的,数字很快就会变大,我们不希望一个包含84065167124611661个单元格的数组只是为了保存字符串hello
。
为了避免这个问题,我们可以创建一个包含n
元素的数组,然后使用散列的剩余部分除以n
作为索引
例如,如果我们想在8个元素的数组中查找hello
的索引:
print hash('hello') % 8 # 5
因此,我们的字典将知道键hello
的值位于索引8。字典就是这样实现的
那么,为什么键上的{2:0,9:0}
不是按顺序排列的呢?这是因为python字典是用8个元素创建的,并且会根据需要增长(更多介绍)
让我们计算索引,以将具有key=2
和key=9
的数据存储在具有n=8
的字典中:
print hash(2) % 8 # 2 [hash(2) = 2 and 2 % 8 = 2]
print hash(9) % 8 # 1 [hash(9) = 9 and 9 % 8 = 1]
这意味着包含字典数据的数组将是:
| index | key | value |
|-------|-----|-------|
| 0 | | |
| 1 | 9 | 0 |
| 2 | 2 | 0 |
| 3 | | |
| 4 | | |
| 5 | | |
| 6 | | |
| 7 | | |
当对其进行迭代时,顺序将在此表示中显示,因此9
将位于2
之前
你可以阅读更多关于这个主题的文章
每次我循环浏览字典(如下图所示),它都会打印出来
按键按递增顺序排列
这只是偶然的。字典是无序的对象集合,可以通过键访问
没有“自动排序”或任何其他类型的排序
只需想一秒钟——设置自己的关键点就是能够通过它们获取,因此关键点有一个“顺序”并不重要——关键点是你知道如何引用每个对象,因为你设置了它的关键点。这使得获取对象的速度非常快;因为它很容易找到。没有重复的键,因此字典内部可以以优化的方式存储,以便快速访问
将其与已排序的列表进行比较(其顺序是有保证的)。在列表中,关键是通过对象在列表中的引用来获取对象,也就是说,通过对象相对于列表中其他对象的位置来获取对象。因此,维持秩序是有意义的
元组与列表相似,因为元组是有序的。元组和列表之间的区别之一是元组一旦设置就不能更改(不能“增长”或“收缩”元组)。为了修改一个元组,必须创建另一个元组。所以要“增长”一个元组,将两个元组相加,得到第三个不同的元组。原来的两个元组保持不变
如果你想知道字典实现背后的技术细节,以及它们是如何工作的,“在引擎盖下”有一个很好的答案,里面有各种各样的信息。如果你想知道Python为什么总是按顺序排列键……答案是它没有 如果您想知道为什么某些特定版本的特定Python实现会将特定键按顺序排列,那么唯一真正的答案就是源代码 对于CPython(您可能正在使用的实现,如果您不知道正在使用哪个实现),源代码位于
Objects/dictobject.c
。它在3.4中发生了戏剧性的变化,在此之前,我认为是2.6/3.2,历史上还有一些其他不太戏剧性的变化。因此,您必须确保查找您真正关心的版本。对于3.4,来源为。它是C语言的,但是有一些很好的注释解释了它的功能。如果您真的想探索它,您甚至可以将它移植到Python并在pdb
下运行它
除非您理解哈希表,否则从阅读代码中可能不明显的一个关键问题是这里有两个“巧合”,而不仅仅是一个。首先,某些版本的CPython在一次构造完一个小dict后,会根据它们的散列值对键进行排序。其次,到目前为止,在CPython的所有版本中,小整数都会散列到它们自己,这与几乎任何其他类型不同——“按散列值排序”也意味着“按值排序”。这就是
print hash(2) % 8 # 2 [hash(2) = 2 and 2 % 8 = 2]
print hash(9) % 8 # 1 [hash(9) = 9 and 9 % 8 = 1]
| index | key | value |
|-------|-----|-------|
| 0 | | |
| 1 | 9 | 0 |
| 2 | 2 | 0 |
| 3 | | |
| 4 | | |
| 5 | | |
| 6 | | |
| 7 | | |