如何使用OrderedDict,一个Python的有序字典。

商业

Python字典(dict类型的对象)不保留元素的顺序;CPython从3.6开始就这样做了,但在其他实现中,这取决于实现,而且是不确定的;语言规范从3.7开始保留了这个顺序。

OrderedDict是在标准库的集合模块中提供的,是一个保留了顺序的字典。使用这个是安全的。

导入集合模块。它被包含在标准库中,不需要被安装。

import collections

如果你写了以下内容,你可以省略以下例子中的集合。

from collections import OrderedDict

以下是关于如何使用OrderedDict的描述。

  • 创建一个OrderedDict对象
  • OrderedDict是dict的一个子类
  • 将元素移到开头或结尾
  • 在任何位置添加一个新元素。
  • 重新排列(重新排序)元素
  • 按键或值对元素进行排序

创建一个OrderedDict对象

构造函数collection.OrderedDict()可以用来创建一个OrderedDict对象。

创建一个空的OrderedDict对象并添加值。

od = collections.OrderedDict()

od['k1'] = 1
od['k2'] = 2
od['k3'] = 3

print(od)
# OrderedDict([('k1', 1), ('k2', 2), ('k3', 3)])

也可以为构造函数指定参数。

你可以使用关键字参数、键值对的序列(如图元组(key, value)),等等。后者可以是一个列表,也可以是一个元组,只要是一个键值对。

print(collections.OrderedDict(k1=1, k2=2, k3=3))
print(collections.OrderedDict([('k1', 1), ('k2', 2), ('k3', 3)]))
print(collections.OrderedDict((['k1', 1], ['k2', 2], ['k3', 3])))
# OrderedDict([('k1', 1), ('k2', 2), ('k3', 3)])
# OrderedDict([('k1', 1), ('k2', 2), ('k3', 3)])
# OrderedDict([('k1', 1), ('k2', 2), ('k3', 3)])

在3.5版本之前,关键字参数的顺序没有被保留,但从3.6版本开始,现在被保留了。

在3.6版本中有所改变。随着PEP 468的接受,OrderedDict构造函数的顺序和传递给update()方法的关键字参数被保留下来。
collections — Container datatypes — Python 3.10.0 Documentation

普通的字典(dict类型的对象)也可以传递给构造函数,但在dict类型不保留顺序的实现中,由它生成的OrderedDict也将不保留顺序。

print(collections.OrderedDict({'k1': 1, 'k2': 2, 'k3': 3}))
# OrderedDict([('k1', 1), ('k2', 2), ('k3', 3)])

OrderedDict是dict的一个子类

OrderedDict是dict的一个子类。

print(issubclass(collections.OrderedDict, dict))
# True

OrderedDict也有与dict相同的方法,获取、改变、添加和删除元素的方法与dict相同。

print(od['k1'])
# 1

od['k2'] = 200
print(od)
# OrderedDict([('k1', 1), ('k2', 200), ('k3', 3)])

od.update(k4=4, k5=5)
print(od)
# OrderedDict([('k1', 1), ('k2', 200), ('k3', 3), ('k4', 4), ('k5', 5)])

del od['k4'], od['k5']
print(od)
# OrderedDict([('k1', 1), ('k2', 200), ('k3', 3)])

详见以下文章。

将元素移到开头或结尾

你可以使用OrderedDict自己的方法move_to_end()来将一个元素移到开头或结尾。

指定键作为第一个参数。默认是移到最后,但如果第二个参数最后一个是假的,就会移到开头。

od.move_to_end('k1')
print(od)
# OrderedDict([('k2', 200), ('k3', 3), ('k1', 1)])

od.move_to_end('k1', False)
print(od)
# OrderedDict([('k1', 1), ('k2', 200), ('k3', 3)])

在任何位置添加一个新元素。

可以创建一个新的OrderedDict对象,在任意位置添加一个新元素。具体来说,这可以在以下流程中完成。

  1. 用list()列出可以用items()方法获得的视图对象。
  2. 在列表的insert()方法中添加一个键值对的元组(key, value)。
  3. 通过传递给构造函数collection.OrderedDict()来创建一个新的对象。
l = list(od.items())
print(l)
# [('k1', 1), ('k2', 200), ('k3', 3)]

l.insert(1, ('kx', -1))
print(l)
# [('k1', 1), ('kx', -1), ('k2', 200), ('k3', 3)]

od = collections.OrderedDict(l)
print(od)
# OrderedDict([('k1', 1), ('kx', -1), ('k2', 200), ('k3', 3)])

insert()把要插入的位置作为第一个参数,把要插入的元素作为第二个参数。

在这个例子中,一个新的对象被分配给了原始变量,而原始对象本身没有添加新的元素。

重新排列(重新排序)元素

替换元素的过程与上面的例子相同。

  1. 用list()列出可以用items()方法获得的视图对象。
  2. 替换列表中的元素
  3. 通过传递给构造函数collection.OrderedDict()来创建一个新的对象。
l = list(od.items())
print(l)
# [('k1', 1), ('kx', -1), ('k2', 200), ('k3', 3)]

l[0], l[2] = l[2], l[0]
print(l)
# [('k2', 200), ('kx', -1), ('k1', 1), ('k3', 3)]

od = collections.OrderedDict(l)
print(od)
# OrderedDict([('k2', 200), ('kx', -1), ('k1', 1), ('k3', 3)])

如果你想指定一个键并替换它,使用index()方法从键的列表中获得索引(位置),如下图所示。

l = list(od.items())
k = list(od.keys())
print(k)
# ['k2', 'kx', 'k1', 'k3']

print(k.index('kx'))
# 1

l[k.index('kx')], l[k.index('k3')] = l[k.index('k3')], l[k.index('kx')]
print(l)
# [('k2', 200), ('k3', 3), ('k1', 1), ('kx', -1)]

od = collections.OrderedDict(l)
print(od)
# OrderedDict([('k2', 200), ('k3', 3), ('k1', 1), ('kx', -1)])

按键或值对元素进行排序

根据可以通过items()方法获得的视图对象,创建一个排序的键值对的图元列表(key, value),并将其传递给构造函数collection.OrderedDict()来创建一个新对象。

排序是通过指定一个匿名函数(lambda表达式)进行的,该函数从一个元组(key, value)中返回一个键或值,作为内置函数sorted()的参数key。

如果你想颠倒顺序,将sorted()的反向参数设置为true。

print(od)
# OrderedDict([('k2', 200), ('k3', 3), ('k1', 1), ('kx', -1)])

od_sorted_key = collections.OrderedDict(
    sorted(od.items(), key=lambda x: x[0])
)
print(od_sorted_key)
# OrderedDict([('k1', 1), ('k2', 200), ('k3', 3), ('kx', -1)])

od_sorted_value = collections.OrderedDict(
    sorted(od.items(), key=lambda x: x[1], reverse=True)
)
print(od_sorted_value)
# OrderedDict([('k2', 200), ('k3', 3), ('k1', 1), ('kx', -1)])