dict(字典)是Python内置的一个类似于map的基本数据结构。它以键值对的形式存储多组数据,方便查询使用。是一款非常好用,应用范围很广的数据结构。
一、dic的定义
dict在其他语言中也称为map,使用键-值(key-value)存储,具有极快的查找速度。
dict利用{key: value, key: value, ...}的方式进行键值对的存储。
举个例子,想象下面的需求:根据同学的名字查找对应的成绩?
如果使用list来存储,则:
names = ['Michael', 'Bob', 'Tracy']
scores = [95, 75, 85]
print(scores[names.index('Michael')])
虽然也能解决,但是索引的很繁琐,难懂,费脑子。
使用dict来存储则有如下:
d = {'Michael': 95, 'Bob': 75, 'Tracy': 85}
print(d['Michael'])
二、dict的使用语法
(1)添加键值对
通过key放入数据到dict中
d['Adam'] = 67
一个key只能对应一个value,多次对一个key放入value,后面的值会把前面的值冲掉.
如果key不存在,dict就会报错
>>> d['Thomas']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'Thomas'
(2) 如何判断key是否存在?
第一种方法: 'Thomas' in d
第二种方法:get()方法
d.get(‘Thomas’) #如不存在返回None
d.get(‘Thomas’, value)#如不存在返回value的值
(3)删除一个key
pop(key) 例如:d.pop('Bob')
务必注意,dict内部存放的顺序和key放入的顺序是没有关系的.
dict中的key必须是不可变对象。
字符串,整数可以。 list不可以。
三、dict的存储机制
dict的存储通过哈希算法(Hash)
通过key计算value的存储位置。为保证hash正确性,key不可变。
那什么是哈希算法呢?
将任意长度的字符串(广义上说:二进制串)通过计算转换为固定长度的字符串。空间换时间。 例如将0-100所有的数字经过哈希函数的运算映射到0-10上。可能会发生冲突。
哈希值越长,冲突的概率越低。
哈希算法避免线性比对的损耗,提升查找(寻址)效率。
举例:根据同学的名字查找成绩。假设待查名字为:n = ‘TracyC’
(1)list做法
names = [‘TracyA', ‘TracyB', 'TracyC']
scores = [95, 75, 85]
查找的效率和
1.names中每个字符串的长度L1(因为要用n来一个个匹配names中的字符串)以及
2.names的长度(需要依次比对直到碰到TracyC为止)有关。
list的查找时间随着元素的增加而增加 因为和L1,L2(尤其是L1)有关。元素越多,查找时间越多。这是显而易见的。
(2)dict方法
以一个足够大段的连续空间(类似于数组)存放value的值。预先以一种方法(哈希函数)将每一个key元素的字符串,全部换成同等长度(二进制长度,比如4字节)的一个整数。这个整数,就是存放value的下标。
查找的时候,将待查找的n利用哈希函数换成一个整数i,接下来用i和dict中的key转换后的整数进行比对。比对成功后,将i对应的下标下的数字取出,这个数字就是n对应的value。
这其中省略了最耗时的字符串比较时间L1,至于整数的匹配,是线性的,可以近似认为与元素规模无关。
(3)list和dict查找效率对比实例
举个例子:
names = [‘TracyA', ‘TracyF', 'TracyM']
list做法,要想找到TracyM,需要比对 6 + 6 + 6 = 18次。然后从scores里取出85
dict做法。
d = {' TracyA ': 95, ' TracyF ': 75, ' TracyM ': 85}
事先已经通过哈希函数,将d变成了 d = {580:95, 585:75, 592:85}
这时计算待查的TracyM的哈希值得到592(这次计算原则上不算在查找的时间里)
查找开始,比对592和d中的key值,三次后找到592,根据592这个index,找到存储在某个大的连续空间里的85.
显然,dict要快得多,但是如果哈希表选不好会造成空间的浪费。
空间换时间。580个空间换来15次的时间。
580,585,592这些数字就是一个哈希函数算出来的。
这个哈希函数就是加法Hash。 也就是把字符串的每一个字符的ASCII码值加起来。
代码如下:
#求n的每一个元素字符串的每一个字符的ascii码值的和。
n = ['TracyA','TracyF','TracyM']
for x in n:
sum = 0
for y in x:
sum += ord(y)
print(sum)
大家思考一下:
按照上述的哈希方法进行计算,TracyA和TracAy这两个人,哈希值一样吗? 显然,会出现冲突,需要解决。不再赘述。
常用的哈希函数 包括:MD5, SHA1, SHA2, SHA-256
哈希能用来做什么?
加密!(因为单向,也即几乎不可逆)
校验!(网站上的防篡改)
区块链技术
网站发布一个视频或者文件,发布对应的MD5值。如果你下载后,用MD5加密后的值和发布的不一致,说明已经被篡改。
四、其他的字典变种
1.默认字典defaultdict
为字典附上默认值。传入像int,list,set这样的工厂函数。
例如:
from collections import defaultdict
dic = defaultdict(list)
print(dic[0])
上述程序得到一个空列表。
2.有序字典
dict是哈希算法存储的,因此,并不按照插入的顺序进行迭代,虽然通常情况下,python的编译器都是有序优化。但是,理论上是无序的。
要想让字典有序,需要有序字典OrderedDict
看下面的例子:
from collections import OrderedDict
dic = OrderedDict()
dic['name'] = 'wangwu'
dic['age'] = 19
dic['score'] = 100
for x in dic:
print(x, dic[x])
运行结果为:
name wangwu
age 19
score 100
学会了就点个赞吧。