作者:@欧礼图
本文章出自企划:麻瓜指南,一个创作者互帮互助共同创作的企划。联系方式见文末尾。


众所周知,字典的一大特性就是元素是无序排列的。那想让字典记住元素的插入顺序该怎么做呢?这就需要用到有序字典这一数据结构了。在正式介绍前,有一点需要读者注意:有序并不是指字典里的元素会按照大小顺序排列,而是说字典会记住所有元素插入的顺序,类似于链表。现在我们就来详细讲解一下有序字典都有什么功能,以及你应该怎么来使用它。

有序字典

定义:python有序字典通常指collections库里的OrderedDict类。它继承python的dict类,也就意味着它和普通字典的使用方法相同,但在某些方法上有所差异。

使用及方法:

  1. popitem(*last*=True)

    popitem函数原是字典内置函数,作用是返回并删除字典中最后一个元素。在OrderedDict里,该函数支持传入last关键字,当last=True时作用与普通字典相同,last=False时改为返回并删除字典首个元素。示例如下:

    1
    2
    3
    4
    5
    6
    7
    8
    >>> from collections import OrderedDict
    >>> test_ordered_dict = OrderedDict.fromkeys('law')
    >>> test_ordered_dict
    OrderedDict([('l', None), ('a', None), ('w', None)])
    >>> test_ordered_dict.popitem(last=False)
    ('l', None) # 删除为字典首个元素
    >>> test_ordered_dict.popitem(last=True)
    ('w', None) # 删除为字典末位元素
  2. move_to_end(*key, last*=True)

    该函数为OrderedDict独有函数,作用为将指定键值对应元素移到首位或末尾。当last=False时,移除首个元素。last=True时,移除末位元素。示例如下:

    1
    2
    3
    4
    5
    6
    7
    8
    >>> from collections import OrderedDict
    >>> test_ordered_dict = OrderedDict.fromkeys('law')
    >>> test_ordered_dict.move_to_end('w', last=False)
    >>> test_ordered_dict
    OrderedDict([('w', None), ('l', None), ('a', None)])
    >>> test_ordered_dict.move_to_end('w', last=True)
    >>> test_ordered_dict
    OrderedDict([('l', None), ('a', None), ('w', None)])

拓展阅读:更多OrderedDict特性可在官网查看

有序集合

概述:有序集合可以利用有序字典中fromkeys函数创建,我们可以将元素转化为key: None的键值对。示例如下:

1
2
3
4
5
6
>>> from collections import OrderedDict
>>> test_ordered_dict = OrderedDict()
>>> test_ordered_dict['key'] = None
>>> test_ordered_dict['anotherKey'] = None
>>> test_ordered_dict
OrderedDict([('key', None), ('anotherKey', None)])

除此之外,一些python第三方库提供了有序集合的实现。这里提供一些参考:
ordered-set
orderedset (Cython based)、boltons-IndexedSet

结语

在python3.7之后,普通字典也支持记住元素的插入顺序。那我们以后就可以用普通字典来代替有序字典了吗?答案很显然是否定的。除了上述多出的方法之外,如果我们想比较两个字典是否相等,有序字典还会自动检查元素的插入顺序。即使两个有序字典内容完全一样,如果插入顺序有所差异,这两个有序字典便不会判定为相等。更多差异请参考官网

我的补充

Ordered Dict

PEP520: Preserving Class Attribute Definition Order

PEP372: Adding an ordered dictionary to collections

PEP372给python提供了OrderedDict类。之后的字典默认保留了顺序,没有走哈希。

Ordered Set

集合是哈希的顺序。

整数作为集合的元素时,位置比较稳定。但是理论上是没有顺序的。

Cython里有OrderedSet。然后这里有一个第三方ordered-set 4.0.2仓库,里面也有一个OrderedSet,兼容了numpy对象。

难道是新版本的python会整合orderedSet和Set类,使Set默认保留顺序?

也可能是社区上谁提了一嘴。