字典和集合相比于列表和元组,字典和集合的性能更优:主要体现在查找、增加和删除操作;
1. 字典和集合基础
- 字典是一系列由键(key)和值(value)配对组成的元素结合
在python3.7+中被确定为有序; - 集合和字典基本相同,主要区别在于:
集合没有键和值的配对,是一系列无序的、唯一的元素组合。 - 字典和集合创建的示例代码如下:
d1 = {'name': 'jason', 'age': 20, 'gender': 'male'}
d2 = dict({'name': 'jason', 'age': 20, 'gender': 'male'})
d3 = dict([('name', 'jason'), ('age', 20), ('gender', 'male')])
d4 = dict(name='jason', age=20, gender='male')
d1 == d2 == d3 ==d4
True
s1 = {1, 2, 3}
s2 = set([1, 2, 3])
s1 == s2
True
- 字典的访问
d = {'name': 'jason', 'age': 20}
d.get('name')
'jason'
d.get('location', 'null')
'null'
- 集合并不支持索引操作:因为集合本质是一个hash表,和列表不一样
可通过value in dict/set判断:
s = {1, 2, 3}
1 in s
True
10 in s
False
d = {'name': 'jason', 'age': 20}
'name' in d
True
'location' in d
False
- 增加、删除、更新
d = {'name': 'jason', 'age': 20}
d['gender'] = 'male' # 增加元素对'gender': 'male'
d['dob'] = '1999-02-01' # 增加元素对'dob': '1999-02-01'
d
{'name': 'jason', 'age': 20, 'gender': 'male', 'dob': '1999-02-01'}
d['dob'] = '1998-01-01' # 更新键'dob'对应的值
d.pop('dob') # 删除键为'dob'的元素对
'1998-01-01'
d
{'name': 'jason', 'age': 20, 'gender': 'male'}
s = {1, 2, 3}
s.add(4) # 增加元素 4 到集合
s
{1, 2, 3, 4}
s.remove(4) # 从集合中删除元素 4
s
{1, 2, 3}
集合是无序的,pop时,要注意
- dict和set的排序:
d = {'b': 1, 'a': 2, 'c': 10}
d_sorted_by_key = sorted(d.items(), key=lambda x: x[0]) # 根据字典键的升序排序
d_sorted_by_value = sorted(d.items(), key=lambda x: x[1]) # 根据字典值的升序排序
d_sorted_by_key
[('a', 2), ('b', 1), ('c', 10)]
d_sorted_by_value
[('b', 1), ('a', 2), ('c', 10)]
s = {3, 4, 2, 1}
sorted(s) # 对集合的元素进行升序排序
[1, 2, 3, 4]
2. 字典和集合的性能
集合和字典内部使用的hash存储,所以它的查找是O(1);
3. 字典和集合内部的工作原理
- 字典:这张表存了hash值、键和值这3个元素;
- set:与字典相比较,区别是hash表中没有键和值的配对,只有单一的元素;
3.1 插入操作
每次想字典或者集合中插入元素时,python首先会计算键的hash值,再和mask=PyDicMinSize - 1进行与操作,计算这个元素应该插入hash表的位置index=hash(key) & mask。
如果hash表中此位置 是空的,那么这个元素就会被插入其中。
而如果这个位置已经被占用,python便会比较这两个元素的hash值和键值是否相等:
1) 两者都相等,表明这个元素已经存在,如果值不同,则更新值;
2)如果两者中有一个不相等,这种情况下成为哈希冲突(hash collision),意思是:两个元素的键不相等,但是hash值相等。在这种情况下,python便会继续寻找表中的空余位置,知道找到位置为止;
3.2 查找操作
python根据key值,index=hash(key) & mask,找到索引,直接取值。
3.3 删除操作
对于删除操作,python会暂时对这个位置的元素,赋予一个特殊的值,等到重新调整hash表的大小时,再将其删除;
4. 同样的问题
1) 下面初始化字典的方式,哪一种更高效?
# Option A
d = {'name': 'jason', 'age': 20, 'gender': 'male'}
# Option B
d = dict({'name': 'jason', 'age': 20, 'gender': 'male'})
tips:其实就是C语言中,内联函数和普通函数的调用区别;
2)字典的键可以是一个列表吗?下面这段代码中,字典的初始化是否正确呢?如果不正确,可以说出你的原因吗?
d = {'name': 'jason', ['education']: ['Tsinghua University', 'Stanford University']}
答案:列表作为key在这里是不被允许的,因为字典中的key要求是不可变的变化的。试想一下,如果key值可以变化,那么字典中就会相互重复的key值,这与字典的定义是相违背的。