轻松初探 Python 篇(五)—dict 和 set 知识汇总

这是「AI 学习之路」的第 5 篇,「Python 学习」的第 5 篇

dict

dict 是 Python 内置的字典类型,熟悉 Java 的同学可以把它类比为 Map。dict 使用键值对来存储(key-value),它的查找速度特别快。

dict 一般用在什么场景呢?假设我们需要根据公司名字查找公司地址,按照我们之前的写法,我们需要先建立两个 list ,一个存储公司名字,一个存储公司总部地址,然后查找公司名字,记录好列表位置,再从地址列表查找到具体元素,你还得保证两个表元素位置必须一一对应。不仅如此,如果表很长,那遍历查找效率将会非常低。

>>> Inc = ['腾讯','阿里','百度']
>>> adress = ['深圳','杭州','北京']
>>> BaiduAdress = adress[Inc.index('百度')]
>>> BaiduAdress
'北京'

我们现在用 dict 实现,使用一个「公司-地址」这样的键值对来进行存储数据,查找的时候,我们只需要输入公司名字,就可以查找到对应的地址,同时,不论 dict 的数据有多少,查找单项的速度都是一样的,而且非常迅速。

>>> Inc_dict = {'腾讯':'深圳','阿里':'杭州','百度':'北京'}
>>> Inc_dict['百度']
'北京'

dict 速度这么快的原理就是使用了空间换取时间的方法,将无限集映射到一个有限集中。通过一个散列函数来计算每一个 key 应该存放在内存中的位置,然后把 value 存储在内存的这个位置上,等到需要取出 key 对应的 value 的时候,只需要通过函数计算出这个位置,然后直接去拿就行了。是不是有点像我们查字典的步骤呢?

通过散列函数求出的最终值就是对应的哈希值(Hash),Java 中的 Map 最常用的实现 HashMap 也是用类似的原理来设计的。Hash 算法也是数据结构中特别重要的一个知识点,所以如果我们计算机的基本功扎实,学哪门语言的时候都是融会贯通的

当然,散列函数本身比较复杂,还要牵扯到冲突的解决问题,简单来说,不同的 key 通过散列函数求得的内存位置可能是一样的,这样就导致了冲突,解决这种冲突的方法有很多,Python 设计者选择了开放定址法,在冲突的时候用另一个不同的函数再计算。在这里我就不深入讨论了,有兴趣的同学可以查阅下相关资料。

我们有很多种方式进行 dict 的初始化,下面几种初始化方式都会获得{"one": 1, "two": 2, "three": 3}

>>> 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

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 之前说过可以看成是集合,所以可以做一些交并集的操作。

原文发布于微信公众号 - WeaponZhi(WeaponZhi)

原文发表时间:2017-11-29

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Python

面向对象的三大特性(封装、继承、多态)

继承 什么是继承 继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类 python中类...

7049
来自专栏用户2442861的专栏

《Effective Modern C++》读书笔记

Note:为避免各种侵权问题,本文并没有复制原书任意文字(代码除外,作者已经声明代码可以被使用)。需要原书完整中文翻译的读者请等待官方译本的发布。

952
来自专栏吴伟祥

编码总结笔记 原

我们知道,在计算机内部,所有的信息最终都表示为一个二进制的字符串。每一个二进制位(bit)有0和1两种状态,因此八个二进制位就可以组合出256种状态,这被称为一...

1136
来自专栏工科狗和生物喵

【计算机本科补全计划】C++ Primer 第二章 【变量和基本类型】

正文之前 C++的数据类型包括 算术类型(int double等)和空类型(void),今天发生了一些很可怕的事情,详情请看正文之后!!我好害怕!! 正文 1、...

37411
来自专栏微信公众号:Java团长

Java开发中如何正确踩坑

之前在这个手册刚发布的时候看过一遍,当时感觉真是每个开发者都应该必读的一本手册,期间还写过一篇关于日志规约的文章:《下一个项目为什么要用 SLF4J》,最近由于...

764
来自专栏C语言C++游戏编程

C语言第一个字符串Hello,C语言基础教程之字符串

C 语言中,字符串实际上是使用 null 字符 '' 终止的一维字符数组。因此,一个以 null 结尾的字符串,包含了组成字符串的字符。

832
来自专栏刘望舒

设计模式(十六)原型模式

前言 公众号有同学留言设计模式,才发现好久没有写设计模式了。关于创建型设计模式只差原型模式没写了,这一篇就来填补这个空缺。 1.原型模式定义 原型模式定义 定...

1899
来自专栏Java帮帮-微信公众号-技术文章全总结

Java基础-day08-超市购物系统总结

Java基础-day08-超市购物系统总结 超市购物小票——自定义类 1案例介绍与演示 将超市购物小票案例中零散数据(名称、货号、单价、计价单位等)封装为货物对...

3746
来自专栏小樱的经验随笔

51Nod 1182 完美字符串(字符串处理 贪心 Facebook Hacker Cup选拔)

1182 完美字符串 ?             题目来源:                         Facebook Hacker Cup选拔    ...

2717
来自专栏AzMark

Python字符串

885

扫码关注云+社区