这是「AI 学习之路」的第 5 篇,「Python 学习」的第 5 篇python
小之的公众号 : WeaponZhi算法
介绍一下 dict 和 set 这两个数据结构。数据结构
dict 是 Python 内置的字典类型,熟悉 Java 的同窗能够把它类比为 Map。dict 使用键值对来存储(key-value),它的查找速度特别快。函数
dict 通常用在什么场景呢?假设咱们须要根据公司名字查找公司地址,按照咱们以前的写法,咱们须要先创建两个 list ,一个存储公司名字,一个存储公司总部地址,而后查找公司名字,记录好列表位置,再从地址列表查找到具体元素,你还得保证两个表元素位置必须一一对应。不只如此,若是表很长,那遍历查找效率将会很是低。学习
>>> Inc = ['腾讯','阿里','百度']
>>> adress = ['深圳','杭州','北京']
>>> BaiduAdress = adress[Inc.index('百度')]
>>> BaiduAdress
'北京'
复制代码
咱们如今用 dict 实现,使用一个「公司-地址」这样的键值对来进行存储数据,查找的时候,咱们只须要输入公司名字,就能够查找到对应的地址,同时,不论 dict 的数据有多少,查找单项的速度都是同样的,并且很是迅速。spa
>>> Inc_dict = {'腾讯':'深圳','阿里':'杭州','百度':'北京'}
>>> Inc_dict['百度']
'北京'
复制代码
dict 速度这么快的原理就是使用了空间换取时间的方法,将无限集映射到一个有限集中。经过一个散列函数来计算每个 key 应该存放在内存中的位置,而后把 value 存储在内存的这个位置上,等到须要取出 key 对应的 value 的时候,只须要经过函数计算出这个位置,而后直接去拿就好了。是否是有点像咱们查字典的步骤呢?设计
经过散列函数求出的最终值就是对应的哈希值(Hash),Java 中的 Map 最经常使用的实现 HashMap 也是用相似的原理来设计的。Hash 算法也是数据结构中特别重要的一个知识点,因此若是咱们计算机的基本功扎实,学哪门语言的时候都是融会贯通的。3d
固然,散列函数自己比较复杂,还要牵扯到冲突的解决问题,简单来讲,不一样的 key 经过散列函数求得的内存位置多是同样的,这样就致使了冲突,解决这种冲突的方法有不少,Python 设计者选择了开放定址法,在冲突的时候用另外一个不一样的函数再计算。在这里我就不深刻讨论了,有兴趣的同窗能够查阅下相关资料。code
咱们有不少种方式进行 dict 的初始化,下面几种初始化方式都会得到{"one": 1, "two": 2, "three": 3}:cdn
>>> a = dict(one=1,two=2,three=3)
>>> b = {'one':1,'two':2,'three':3}
>>> c = dict(zip(['one','two','three'],[1,2,3]))
>>> d = dict([('two',2),('one',1),('three',3)])
>>> e = dict({'three':3,'one':1,'two':2})
>>> a == b == c == d == e
True
复制代码
除了经过初始化之外,还能够经过 key 来放入值,再次传入相同 key ,不一样 value,将会覆盖前面传入的 value。若是某个 key 不存在,获取该 key 的 value 将会报 KeyError 错误。
>>> Inc_dict['途牛'] = '南京'
>>> Inc_dict['途牛']
'南京'
>>> Inc_dict['途牛'] = '金陵'
>>> Inc_dict['途牛']
'金陵'
>>> Inc_dict['小米']
KeyError:'小米'
复制代码
为了防止获取 key 不存在的状况。咱们能够用 in 来判断 dict 中是否已经存储过以这个 key 来存储的键值对。或者用 get() 方法来获取 value,若是 key 不存在,get() 将返回 None,能够设置一个参数来表示 key 不存在时候的默认返回值。
>>> '小米' in Inc_dict
False
>>> Inc_dict.get('小米')
>>> Inc_dict.get('小米','北京')
北京
复制代码
经过 pop(key) 方法,来返回并删除对应的 value:
>>> Inc_dict.pop('腾讯')
'深圳'
>>> Inc_dict
{'阿里':'杭州','百度':'北京','途牛':'金陵'}
复制代码
最后介绍下 dict 的迭代,咱们知道 list 迭代能够简单的经过 for 来遍历,dict 迭代须要多作一些操做。
>>> d = {'a':1,'b':2,'c':3}
>>> for key in d:
... print(key)
...
'a'
'c'
'b'
复制代码
dict 默认的迭代方式是迭代 key ,若是你须要迭代 value 能够经过 d.values() 来获取 value 的列表
>>> for value in d.values()
... print(value)
...
1
3
2
复制代码
固然,你还能够同时迭代 key 和 value
>>> for k, v in d.items():
... print(k, v)
...
a 1
c 3
b 2
复制代码
细心的同窗必定发现了迭代的顺序和咱们初始化定义的顺序是不一样的,以前也提到了,dict 内部存放顺序是根据散列函数决定的,因此最后的存放顺序不必定和插入顺序一致,那咱们迭代顺序显然是不肯定的了。
dict 的设计是典型的以空间换取时间,你们学习 Python 越深刻就会发现 Python 的设计里有不少这样的设计, Python 设计的时候,大概已经不是内存最大就 4,500K 的年代了吧(手动嬉笑)。因此 dict 的特色就是,查找和插入的速度很是快,而且不随元素数量的增加而变慢。
注意:key 必须是不可变对象(字符串,整数等),若是 key 是 list,就会报错 TypeError: unhashable type: 'list',tuple 虽然是不可变对象,但若是传入的 tuple 元素有可变对象,依然会报错。
>>> d = {'a':1}
>>> d = {'a':1,(1,):2}
>>> d = {'a':1,(1,):2,(1,[1]):3}
TypeError: unhashable type: 'list'
复制代码
set 和 dict 很像,不过 set 不存储键值对,你能够把它想像成只存储 key 的 dict,也能够理解成数学中的无序无重复集合这个概念。因此在 set 中是没有重复元素的,也只能存放不可变元素。咱们能够经过一个 list 来建立 set。一样,也是用大括号表示。
>>> s = set([1,2,3])
>>> s
{1,2,3}
>>> s = set([1,2,3,3,3])
>>> s
{1,2,3}
复制代码
咱们能够看到,重复的元素自动被过滤了,同时 set 也是无序的,虽然建立时候显示看起来好像是有序的。咱们来看看 set 的一些经常使用方法。
>>> s.add(4)
>>> s
{1,2,3,4}
>>> s.add(4)
>>> s
{1,2,3,4}
复制代码
add(key)添加元素到 set 中,但添加剧复元素将不会生效
>>> s.remove(4)
>>> s
{1,2,3}
>>> s.remove(4)
KeyError: 4
>>> s1 = {1,2,3}
>>> s2 = {2,3,4}
>>> s1 & s2
{2,3}
>>> s1 | s2
{1,2,3,4}
复制代码
remove(key)删除元素,若是 key 不存在会报错。同时,set 以前说过能够当作是集合,因此能够作一些交并集的操做。
欢迎关注个人公众号