深入dict与set

如果一件事你不相信自己能做到,那你就真的做不到!因为你连希望都丢掉了,你又怎么能做到?

DICT

dict,python中的字典,有key和value对应,属于mapping(关系映射)类型。通过isinstance(dict,Mapping)可以判断

from collections import Mapping
a = {'a':'a'}
print(isinstance(a,Mapping))

返回结果:

True

获取值

使用get和[]直接取值都可以,后者如果取值不存在就报错,前者不会,如果是修改键对应的值的话,使用第二种方法。

a = {'user':'langzi'}
print(a['user'])
print(a.get('user'))
# 获取值
a['user']='admin'
# 改变值

返回结果:

langzi
langzi

你还可以获取字典的所有键或者所有值,使用keys和values

啊 = {'user': 'langzi', 'age': 18}
print(啊)
print(啊.keys())
print(啊.values())
# 注意中文变量在python3中才可用

返回结果:

{'user': 'langzi', 'age': 18}
dict_keys(['user', 'age'])
dict_values(['langzi', 18])

还可以使用setdefault获取,setdefault() 方法和 get() 方法类似,返回指定键的值,如果键不在字典中,将会添加键并将值设置为一个指定值,默认为None。

a = {'user': 'langzi', 'age': 18}
print(a.setdefault('user','aaaaaaaaaaaa'))
print(a.setdefault('users','aaaaaaaaaaaa'))

返回结果:

langzi
aaaaaaaaaaaa

清空字典

直接将字典清空,包括内容与格式。

a = {'user':'langzi'}
a.clear()
print(a)
b = {'user':{'user':'admin'},'age':18}
b.clear()
print(b)

返回结果:

{}
{}

删除字典中的某一对键值

使用del即可,举个例子:

a = {'user': 'langzi', 'age': 18}
del a['user']
print(a)

返回结果:

{'age': 18}

复制字典

使用dict.copy()返回一个拷贝的对象,其实就是调用copy.copy()浅拷贝,修改拷贝后的对象会影响到原对象的值,因为浅拷贝只把值都是指向同一个对象。

生成字典

根据你的列表或者数组的内容,变成字典的键,值就是你自己随便折腾的,举两个例子。

a = ['user1','user2','user3']
b = dict.fromkeys(a,'None')
print(b)

返回结果:

{'user1': 'None', 'user2': 'None', 'user3': 'None'}

当然也可以这么写:

import random
a = {k:random.randint(1000,1020) for k in range(10)}
print(a)

返回结果:

{0: 1009, 1: 1008, 2: 1001, 3: 1008, 4: 1019, 5: 1012, 6: 1010, 7: 1012, 8: 1019, 9: 1013}

字典合并

就像列表使用extend(本质上是调用append)合并,字典也有相似的用法,使用update。

a = {'user':'langzi'}
b = {'age':18}
a.update(b)
# 还可以这样传入a.update(home='china')
print(a)

返回结果:

{'user': 'langzi', 'age': 18}

判断是否有键

使用dice.has_key(key)即可,存在就返回True

获取键的总和

使用len(dict)即可。

循环字典

这个比较简单的,如果是for x in dict的话就是循环字典的键,如果for x,y in dict.iters()那么同时循环字典的键和值。

更多具体方法

传送门1

传送门2

继承字典

其实list和dict都是可以被继承的,因为他们的数据结构本来就是一个类,当然可以被继承,但是不建议这么做。

SET

SET:集合,frozenset:不可变集合,集合是有无序和不重复的两个特点,所以常用来做去重,并且集合也是用{}包围起来的。

比如:

s = set('aaaaa')
print(s)

返回结果:

a

如果你直接使用a={},a.add(1)这样事会报错的,你比如先实例化一个集合,比如a=set(),然后再a.add(1)就可以。

添加数据

使用set.add(‘xxx’),但是如果是frozenset是无法添加修改数据的。

合并数据

使用set.update(‘xaxaxa’)

删除数据

set.remove('xxx'):删除xxx,不存在xxx报错    
set.pop():删除并返回一个不确定元素
set.discard('xxx'):删除xxx,不存在xxx不报错

取交集与并集

交集:两个集合中都有的元素。并集:两个集合中所有的元素。

a = {'a','b','c'}
b = {'a','e','f'}
print(a|b)
# 取并集
print(a&b)
# 取交集

返回结果:

{'e', 'f', 'a', 'b', 'c'}
{'a'}

再举个例子:

a = {'a','b','c'}
b = {'a','e','f'}
print(a-b)
# 找出a中b没有的元素

返回结果:

{'b', 'c'}

SET与DICT都是使用hash存储,时间复杂度很低,相对来说性能很高。

dict与set的一些特性

  1. dict查找性能远大于list
  2. 在list中随着list数据增大,查找时间也会增大
  3. 在dict中随着dict元素增大,查找时间不会增大(因为dict存储原理是用哈希表)
  4. set的原理和dict一样,也是走哈希表方法(不可变对象)
  5. dict内存花销大,python中内部的对象都是dict进行包装的
  6. dict的顺序和元素添加顺序有关,添加数据有可能改变已有数据的顺序

概念:python中的dict并没有采用map中的红黑树结构做关联,而是使用效率更高的散列表,在最优情况下,散列表能够提供O(1)的搜索效率。

散列表的基本思想是:通过一定的函数将需要搜索的键值映射为一个整数,根据这个整数作为索引去访问某片连续的内存区域。用于映射的函数称为映射函数,映射所产生的值称为散列值(hash value)。散列函数对搜索效率有直接的决定性作用。在使用散列函数将不同的值可能映射到相同的散列值,这个时候就需要冲突解决(装载率大于2/3时,冲突的概率就会大大增加)

冲突解决在python中使用的是开放定址法,就是通过一个二次探测函数f,计算下一个位置,一直到找到下一个可用的位置为止,在这个过程中会到达多个位置,这些位置就形成了一个“冲突探测链”,这个冲突探测链在查找某个元素的时候起到重要作用,所以在删除某个位置上的元素,不能直接将这个位置的内容删除,如果删除的话,则导致后续依赖于这个位置的其他值就都无法寻找到了,所以只能进行“伪删除”(通过给元素设置状态,dummy态,表示没有存储具体的值但是还会用到的废弃态)链接

散列表通过一个函数将键值映射为一个整数,再将整数作为索引值访问内存。用于映射的函数称为散列函数,映射后的值为散列值。散列会发生冲突,解决散列冲突的方法有很多,python使用的是开放定址法,当发生冲突再次探测可用位置,形成探测链,探测链如果要删掉中间一个元素,会使用伪删除处理,防止链断开搜索失败。链接

坚持原创技术分享,您的支持将鼓励我继续创作!
------ 本文结束 ------

版权声明

LangZi_Blog's by Jy Xie is licensed under a Creative Commons BY-NC-ND 4.0 International License
由浪子LangZi创作并维护的Langzi_Blog's博客采用创作共用保留署名-非商业-禁止演绎4.0国际许可证
本文首发于Langzi_Blog's 博客( http://langzi.fun ),版权所有,侵权必究。

0%