FeelingLife FeelingLife
首页
  • Go

    • Go基础知识
  • Python

    • Python进阶
  • 操作系统
  • 计算机网络
  • MySQL
  • 学习笔记
  • 常用到的算法
  • Docker
  • Kubernetes
  • Observability
  • 容器底层
其他技术
  • 友情链接
  • 收藏
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

xuqil

一介帆夫
首页
  • Go

    • Go基础知识
  • Python

    • Python进阶
  • 操作系统
  • 计算机网络
  • MySQL
  • 学习笔记
  • 常用到的算法
  • Docker
  • Kubernetes
  • Observability
  • 容器底层
其他技术
  • 友情链接
  • 收藏
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • Pythonic思维

  • 列表和字典

    • 列表和元组
    • 字典和集合
      • 底层结构
      • 性能
        • dict
        • set
      • 其他
  • 底层数据结构

  • 《python进阶》
  • 列表和字典
xuqil
2022-04-29
目录

字典和集合

# 字典和集合

字典(dicts, dictionaries dictionaries (opens new window))是一系列由键(key)和值(value)配对组成的元素的集合,底层是哈希表。字典存储任意数量的对象,每个对象都由唯一的字典key标识。

字典通常也称为maps, hashmaps, lookup tables,或 associative arrays。它们允许高效查找、插入和删除与给定键关联的任何对象。相比于列表和元组,字典的性能更优,特别是对于查找、添加和删除操作,字典都能在常数时间复杂度内完成。

在 Python3.7+,字典被确定为有序(注意:在 3.6 中,字典有序是一个 implementation detail,在 3.7 才正式成为语言特性,因此 3.6 中无法 100% 确保其有序性),而 3.6 之前是无序的,其长度大小可变,元素可以任意地删减和改变。

>>> book = {
...     "a": 1,
...     "b": 2,
...     "c": 3,
... }
>>> squares = {x: x * x for x in range(6)}
>>> book["a"]
1
>>> "a" in book
True
>>> squares
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
1
2
3
4
5
6
7
8
9
10
11
12

而集合和字典基本相同,唯一的区别,就是集合没有键和值的配对,是一系列无序的、唯一的元素组合。

>>> book = {1,2,3,4,5,5}
>>> book
{1, 2, 3, 4, 5}
1
2
3

# 底层结构

字典和集合的内部结构都是一张哈希表。

  • 对于字典而言,这张表存储了哈希值(hash)、键和值这 3 个元素。
  • 而对集合来说,区别就是哈希表内没有键和值的配对,只有单一的元素了。

# 性能

# dict

为dict对象列出的平均事例时间假设对象的哈希函数足够健壮,从而使碰撞不常见。一般情况下,假设参数中使用的关键点是从所有关键点集中均匀随机选择的。

注意,dict有一条快速路径(实际上)只处理str键;这不会影响算法的复杂性,但会显著影响常量因素:典型程序完成的速度。

Operation Average Case Amortized Worst Case
k in d O(1) O(n)
Copy[3] O(n) O(n)
Get Item O(1) O(n)
Set Item[1] O(1) O(n)
Delete Item O(1) O(n)
Iteration[3] O(n) O(n)

# set

跟字典dict类似。

Operation Average case Worst Case notes
x in s O(1) O(n)
Union s|t O(len(s)+len(t)) (opens new window)
Intersection s&t O(min(len(s), len(t))) O(len(s) * len(t)) replace "min" with "max" if t is not a set
Multiple intersection s1&s2&..&sn (n-1)*O(l) where l is max(len(s1),..,len(sn))
Difference s-t O(len(s))
s.difference_update(t) O(len(t))
Symmetric Difference s^t O(len(s)) O(len(s) * len(t))
s.symmetric_difference_update(t) O(len(t)) O(len(t) * len(s))
  • 从源代码 (opens new window)中可以看出,集差异 st 或 s.difference(t) ( set_difference() ) 和就地集差异 s.difference_update(t) ( set_difference_update_internal() ) 的复杂性是不同的!第一个是 O(len(s))(对于 s 中的每个元素,如果不在 t 中,则将其添加到新集合中)。第二个是 O(len(t)) (对于 t 中的每个元素都将其从 s 中删除)。所以必须注意哪个是首选的,这取决于哪个是最长的集合以及是否需要新的集合。
  • 要执行像 st 这样的集合操作,s 和 t 都需要是集合。但是,即使 t 是任何可迭代的,您也可以执行等效方法,例如 s.difference(l),其中 l 是一个列表。

# 其他

高效创建字典

  • 字典生成式
  • {}
  • dict()

跟列表一样,字典也有它的语法糖,且比dict()定义字典更高效。

# 使用{}
d = {'name': 'go', 'age': 10, 'python': '20'}

# 使用dict函数
d = dict({'name': 'go', 'age': 10, 'python': '20'})
1
2
3
4
5

使用dis分析:

>>> def create_dict1():
...     return {'name': 'go', 'age': 10, 'python': '20'}
...
>>> def create_dict2():
...     return dict({'name': 'go', 'age': 10, 'python': '20'})
...
>>> dis.dis(create_dict1)
  2           0 LOAD_CONST               1 ('go')
              2 LOAD_CONST               2 (10)
              4 LOAD_CONST               3 ('20')
              6 LOAD_CONST               4 (('name', 'age', 'python'))
              8 BUILD_CONST_KEY_MAP      3
             10 RETURN_VALUE
>>> dis.dis(create_dict2)
  2           0 LOAD_GLOBAL              0 (dict)
              2 LOAD_CONST               1 ('go')
              4 LOAD_CONST               2 (10)
              6 LOAD_CONST               3 ('20')
              8 LOAD_CONST               4 (('name', 'age', 'python'))
             10 BUILD_CONST_KEY_MAP      3
             12 CALL_FUNCTION            1
             14 RETURN_VALUE
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

比较创建时间:

python -m timeit "d = {'name': 'go', 'age': 10, 'python': '20'}"
# 5000000 loops, best of 5: 98.7 nsec per loop
python -m timeit "d = dict({'name': 'go', 'age': 10, 'python': '20'})"
# 1000000 loops, best of 5: 219 nsec per loop
1
2
3
4

字典的键需要是可哈希的值

字符串和数字等不可变类型是可哈希的,并且可以很好地用作字典键。也可以将tuple对象用作字典键,只要它们本身只包含可散列类型。

但对于列表这种可变化类型,是不可以作为字典的键的。

上次更新: 2024/05/29, 06:25:22
列表和元组
python内置的堆、栈和队列

← 列表和元组 python内置的堆、栈和队列→

最近更新
01
VXLAN互通实验
05-13
02
VXLAN
05-13
03
VLAN
05-13
更多文章>
Theme by Vdoing | Copyright © 2018-2025 FeelingLife | 粤ICP备2022093535号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式