将字典转换为有序字典

160

我在使用Python 2.7的Raspbian上遇到了一些问题,无法正确使用collections.OrderedDict类。我尝试打印两个有序字典以便进行比较,但无论我怎么尝试,这些字典总是以通常的无序方式打印出来。这对于精确比较非常重要。

这是我在我的Raspberry Pi上得到的输出:

import collections

ship = {"NAME": "Albatross",
         "HP":50,
         "BLASTERS":13,
         "THRUSTERS":18,
         "PRICE":250}

ship = collections.OrderedDict(ship)

print ship
# OrderedDict([('PRICE', 250), ('HP', 50), ('NAME', 'Albatross'), ('BLASTERS', 13), ('THRUSTERS', 18)])

显然有些不对劲,因为它打印了函数调用,并将键和值组放入了一个嵌套列表中...

这是我在我的电脑上运行类似内容得到的结果:

import collections

Joe = {"Age": 28, "Race": "Latino", "Job": "Nurse"}
Bob = {"Age": 25, "Race": "White", "Job": "Mechanic", "Random": "stuff"}

#Just for clarity:
Joe = collections.OrderedDict(Joe)
Bob = collections.OrderedDict(Bob)

print Joe
# OrderedDict([('Age', 28), ('Race', 'Latino'), ('Job', 'Nurse')])
print Bob
# OrderedDict([('Age', 25), ('Race', 'White'), ('Job', 'Mechanic'), ('Random', 'stuff')])

这次,它是按顺序的,但不应该打印其他东西,对吧?(把它放进列表并显示函数调用。)

我犯了什么错误?这不应该与Python pi版本有任何关系,因为它只是Linux版本。


4
注意:OrderedDict 按照插入顺序进行排序,而不是按字母数字键的顺序。 - el.pescado - нет войне
6个回答

238

您首先创建一个字典,然后将该字典传递给OrderedDict。对于Python版本小于3.6(*),在进行此操作时,顺序不再正确。字典本质上是无序的。

改为传入元组序列:

ship = [("NAME", "Albatross"),
        ("HP", 50),
        ("BLASTERS", 13),
        ("THRUSTERS", 18),
        ("PRICE", 250)]
ship = collections.OrderedDict(ship)
当你打印 OrderedDict 时,看到的是它的 表示形式,这完全是正确的。 OrderedDict([('PRICE', 250), ('HP', 50), ('NAME', 'Albatross'), ('BLASTERS', 13), ('THRUSTERS', 18)]) 只是向你展示了一个可重现的表示形式,它显示了 OrderedDict 的内容。
(*): 在 CPython 3.6 实现中,dict 类型已经更新为使用更内存高效的内部结构,这个更新有一个愉快的副作用,即保留插入顺序,并扩展到问题中所示的代码没有问题。截至 Python 3.7,Python 语言规范 已经更新为要求所有 Python 实现必须遵循这种行为。请参见我的另一个回答以获取详细信息,了解为什么您仍然可能需要在某些情况下使用 OrderedDict()

好的,那么OrderedDict会为我创建字典吗?另外,如果要打印不可重现的表示形式,我可以直接打印使用OrderedDict的变量吗?例如: print ship??谢谢 :) - ninthpower
@pythonpiboy:打印“ship”将打印它所引用的值,因此它将打印“OrderedDict”表示。 - Martijn Pieters
3
以你所描述的方式,OrderedDict正在创建一个有序的“列表”。这不是违背了它的目的吗?它只是创建了一个元素的列表,而不是带有键和值的字典... - ninthpower
9
该类型同时兼具映射(mapping)和保持顺序的功能。要创建一个带有顺序的该类型对象,你需要按照顺序提供所需的元素。由于标准字典(除了 PyPI 或 Python 3.6+ 版本以外的任何版本)无法实现该功能,因此你需要给它传入一个元组列表。一旦创建了 OrderedDict 对象,它就是一个字典。 - Martijn Pieters
4
听起来混淆是因为假设有序字典“应用”一种排序,而不仅仅是保留顺序。我肯定假设它会在创建时对输入进行排序,或者无论何时插入项,items()函数都会返回已排序的项。但实际上,它只保留您提供的任何排序。 - whiterook6
2
@whiterook6:这不是一个排序字典。它是一个有序字典,记录键值对的顺序并允许您重新排序这些对。与有序序列相比,如列表。 - Martijn Pieters

41

如果您无法编辑代码中定义字典的部分,仍然可以在任何时候以任何方式对其进行排序,如下所示:

from collections import OrderedDict

order_of_keys = ["key1", "key2", "key3", "key4", "key5"]
list_of_tuples = [(key, your_dict[key]) for key in order_of_keys]
your_dict = OrderedDict(list_of_tuples)

12

大多数情况下,当我们需要自定义排序而不是像 ASC 等通用排序时,我们会选择 OrderedDict。

以下是建议的解决方案:

import collections
ship = {"NAME": "Albatross",
         "HP":50,
         "BLASTERS":13,
         "THRUSTERS":18,
         "PRICE":250}

ship = collections.OrderedDict(ship)

print ship


new_dict = collections.OrderedDict()
new_dict["NAME"]=ship["NAME"]
new_dict["HP"]=ship["HP"]
new_dict["BLASTERS"]=ship["BLASTERS"]
new_dict["THRUSTERS"]=ship["THRUSTERS"]
new_dict["PRICE"]=ship["PRICE"]


print new_dict

这将是输出:

OrderedDict([('PRICE', 250), ('HP', 50), ('NAME', 'Albatross'), ('BLASTERS', 13), ('THRUSTERS', 18)])
OrderedDict([('NAME', 'Albatross'), ('HP', 50), ('BLASTERS', 13), ('THRUSTERS', 18), ('PRICE', 250)])

注意:新的有序字典在删除条目时保持其排序顺序。但是当添加新键时,键将附加到末尾且排序不会被维护。(官方文档)


6

您可以使用一行代码将旧字典转换为有序字典:

from collections import OrderedDict
ordered_dict = OrderedDict(sorted(ship.items())

默认的排序键是字典键,因此新的ordered_dict按照旧字典的键进行排序。


这是正确答案。 - WhyWhat

1
使用 dict.items(),代码可以非常简单,如下所示:
ship = collections.OrderedDict(ship.items())

实际上,ship.items() 不是有序的。你可以通过简单地打印 ship.items() 来检查它。 - noureddine-as

0
希望这可以作为另一种答案。干杯!

import collections

ship = {"NAME": "Albatross",
         "HP":50,
         "BLASTERS":13,
         "THRUSTERS":18,
         "PRICE":250}

# unsequenced key value pair in the dict
print ship

# before using inherent dict for creating an OrderedDict
print collections.OrderedDict(ship)
# OrderedDict([('PRICE', 250), ('HP', 50), ('NAME', 'Albatross'), ('BLASTERS', 13), ('THRUSTERS', 18)])

list_key = ["NAME","HP","BLASTERS","THRUSTERS","PRICE"]
ordered_list = [(key,ship[key]) for key in list_key]
ordered_ship = collections.OrderedDict(ordered_list)

print ordered_ship
# OrderedDict([('NAME', 'Albatross'), ('HP', 50), ('BLASTERS', 13), ('THRUSTERS', 18), ('PRICE', 250)])


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接