迭代字典按排序顺序返回键

时间:2014-08-10 15:14:06

标签: 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 }

我想迭代这个字典并打印出密钥。每次我遍历字典(如下所示)时,它都会按顺序打印键。

这就是我想要它做的,但我想知道,为了我自己的知识,为什么会发生这种情况?每次都按递增顺序自动排序吗?正如你在上面的字典中看到的那样,键显然没有按顺序递增,但下面的输出按顺序打印它们。

我只是想获得一个清晰的理解,任何帮助将不胜感激。感谢

实施例

for i in a:
    print i

输出

1
5
11
14
15
16
17
19
20
25
100

4 个答案:

答案 0 :(得分:3)

字典中的整数并不总是按键排序:

a = {2:0, 9:0}
print a.keys()  # [9, 2]

Python词典是 Hash Tables ,它是一种特殊的数组,其中存储值的单元格的索引 派生在上应用特殊功能(让我们称之为hash功能)。 这样,如果要检索特定,您可以再次计算hash功能,将返回与之前相同的结果,获取存储的索引。

hash函数将 most 类型的数据转换为整数:

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

正如您所看到的那样,数字很快就会变大,我们不希望拥有一个包含 840651671246116861 单元格的数组,只是为了保存字符串hello。 为了避免这个问题,我们可以使用n元素创建一个数组,然后使用 hash 的剩余部分除以n作为索引。 / p>

例如,如果我们想在 8 元素的数组中找到hello的索引:

print hash('hello') % 8   # 5

因此,我们的字典会知道密钥hello位于索引 8 。这就是字典的实现方式。

那么,为什么{2:0, 9:0}没有按键排序?这是因为python词典是用 8 元素创建的,并且根据需要增长(更多关于here)。

让我们计算索引,将key = 2key = 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之前。

您可以阅读有关here主题的更多信息。

答案 1 :(得分:2)

如果你想知道为什么Python总是把键按顺序排列......答案就是它没有。

如果您想知道为什么某些特定版本的Python的某些特定版本将您的特定键按排序顺序排列,那么唯一真正的答案就是源代码。

对于CPython(你可能正在使用的实现,如果你不知道你正在使用哪一个),源代码在Objects/dictobject.c。它在3.4中发生了巨大变化,在此之前......我认为2.6 / 3.2,并且历史上还有一些其他不那么戏剧性的变化。因此,您必须确保查找您真正关心的版本。对于3.4,源位于http://hg.python.org/cpython/file/3.4/Objects/dictobject.c。它在C中,但有一些很好的评论解释它在做什么。如果你真的想要探索它,你甚至可以将它移植到Python并在pdb下运行它。

除非你理解哈希表,否则读取代码可能不明显的一个关键问题是两个"巧合"在这里,不只是一个。首先,CPython的某些版本,当给出一个小的dict同时构建时,将按键的哈希值按顺序排列。其次,到目前为止,在所有版本的CPython中,小整数都是哈希,所以 - 几乎与其他任何类型不同 - "按哈希值排序"也意味着"按价值排序"。

答案 2 :(得分:1)

  

每当我循环浏览字典(如下所示)时,它就会打印出来   按键递增。

这只是偶然的。字典是无序对象集合,可通过键访问。

没有“自动排序”或任何其他类型。

只需考虑它一秒钟 - 设置自己的密钥的全部要点是能够通过它们获取,因此密钥具有“订单”并不重要 - 关键是你知道如何引用每个对象,因为你设置了它的键。这样可以非常快速地获取对象;因为它很容易找到。没有重复的键,因此内部字典可以以优化的方式存储以便快速访问。

将此与已订购的清单进行比较(并确保其订单)。在列表中,重点是通过列表中的引用来获取对象 - 即,相对于列表中其他对象的位置。因此,维持秩序是有道理的。

元组类似于列表,因为它们是有序的。元组和列表之间的区别之一是元组一旦设置,就无法更改(不能“增长”或“缩小”元组)。要修改元组,您必须创建另一个元组。因此,为了“增长”一个元组,将两个元组组合在一起以获得第三个​​不同的元组。最初的两个元组没有变化。

如果您想了解字典实施背后的技术细节以及它们如何在“引擎盖下”工作this question对所有各种信息都有很好的答案。

答案 3 :(得分:-2)

doc说:

  

最好将字典视为一组无序的键:值   对,要求键是唯一的

与Python列表或元组不同,dict对象中的键和值对没有任何特定的顺序。虽然在实例化字典时键值对按特定顺序排列,但只需调用字典就可以看到它们的存储顺序不同。 然后,如果要对它们进行排序,只需使用内置的sorted方法