Python内置数据结构(集合与字典)及Python解析式、生成器
2019-04-11 21:33
323 查看
Python内置数据结构
#####此篇文章来源于我的老师Wayne,仅作记录以备复习
集set
- 约定
set翻译为集合
collection翻译为集合类型,是一个大概念 - set
可变的、无序的、不重复 的元素的集合
set定义 初始化
- set() -> new empty set object
- set(iterable) -> new set object
注意
- s1={}为字典,而不是集合
- s2={[1],(1),1} 错误,set的元素要求必须可以hash
- set 的元素不可以使用索引
- set可以迭代
set增加
- add(elem)
增加一个元素到set中
如果元素存在,什么都不做
- update(*others)
-
合并其他元素到set集合中来
- 参数others必须是可迭代对象
- 就地修改
set删除
- remove(elem)
-
从set中移除一个元素
- 元素不存在,跑出KeyError异常
- discard(elem)
-
从set中移除一个元素
- 元素不存在,什么都不做
- pop() -> item
-
移除并返回任意的元素
- 空集返回KeyError异常
- clear()
-
移除所有元素
set修改、查询
- 修改
-
要么删除,要么加入新的元素
- 查询
-
非线性结构,无法索引
- 遍历
-
可以迭代所有元素
- 成员运算符
-
in 和 not in 判断元素是否在set中
- 效率是O(1) ,set用元素的hash值进行查询
set成员运算符的比较
pass
set和线性结构
- 线性结构的查询时间复杂度是O(n),即随着数据规模的增大而增加耗时
- set、dict等结构,内部使用hash值作为key,时间复杂度可以做到O(1),查询时间和数据规模无关
- 可hash
-
数据行int、float、complex
- 布尔型True、False
- 字符串string、bytes
- tuple
- None
- 以上都是不可变类型,是可哈希类型,hashable
- set的元素必须是可hash的
集合
- 基本概念
- 全集
所有元素的集合。例如实数集,所有实数组成的集合就是全集
- 子集subset和超集superset
一个集合A所有元素都在另一个集合B内,A是B的子集,B是A的超集
- 真子集和真超集
A是B的子集,且A不等于B,A就是B的真子集,B是A的真超集
- 并集:多个集合合并的结果
- 交集:多个集合的公共部分
- 差集:集合中出去和其他集合公共部分
集合运算
并集
- 将两个集合A和B的所有的元素合并到一起,组成的集合称作集合A与集合B的并集
- union(*others)
返回和多个集合合并后的新的集合 - | 运算符重载
等同于union - update(*others)
和多个集合合并,就地修改 - |=
等同 update
交集
- 集合A和B,由所有属于A属于B的元素组成的集合
- intersection(*others)
返回和多个集合的交集 - &
等同于 intersection - intersection_update(*others)
获取和多个集合的交集,并就地修改 - &=
等同于 intersection_update
差集
- 集合A和B,由所有属于A且不属于B的元素组成的集合
- difference(*others)
返回和多个集合的差集 - –
等同于difference - difference_update(*others)
获取和多个集合的差集并就地修改 - –=
等同difference_update
对称差集
- 集合A和B,由所有属于A且不属于B的交集元素组成的集合,记做(A-B)U(B-A)
- symmetric_difference(other)
返回和另一个集合的差集 - ^
等同于symmetric_differece - symmetric_difference_update(other)
获取和另一个集合的差集并就地修改 - ^=
等同symmetric_difference_update
- issubset(other)、<=
判断当前集合是否是另一个集合的子集 - set1 < set2
判断set1是否是set2的真子集 - issuperset(other)、>=
判断当前集合是否是other的超集 - set1 > set2
判断se 4000 t1是否是set2的真超集 - isdisjoint(other)
当前集合和另一个集合有没有交集
没有交集,返回True
字典dict
- key-value 键值对的数据集合
- 可变的、无序的、key不重复
字典dict定义 初始化
- d = dict() 或者 d = {}
- dict(**kwargs) 使用 name=value对 初始化一个字典
- dict(iterable,**kwarg)使用可迭代对象和 name=value对 构造字典,不过可迭代对象的元素必须是一个二元 结构 d = dict(((1,‘a’),(2,‘b’))) 或者 d = dict(([1,‘a’],[2,‘b’]))
-
d = dict.fromkeys(range(5))
字典元素的访问
- d[key] 返回key对应的值value
- key不存在抛出KeyError异常
-
返回key对应的值value
-
返回key对应的值value
字典增加和修改
- d[key] = value 将key对应的值修改为 value
-
key不存在添加新的kv对
-
使用另一个字典的kv对更新本字典
例:
d.update(red=1) d.update((('red‘,2),)) d.update({'red':3})
字典删除
- pop(ley[,default]) key 存在,移除它,并返回它的value
- key 不存在,返回给定的default
- default未设置,key不存在,则抛出KeyError异常
-
移除并返回一个任意的键值对
-
清空字典 (一般情况不建议使用)
del 语句
a = True b = [6] d = {'a':1,'b':b,'c':[1,3,5]} del a del d['c'] del b[0] c=b del c del b b = d['b']
del a[‘c’] 看着像删除了一个对象,本质上减少了一个对象的引用,del 实际上删除的是名称,而不是对象(引用计数减一)
字典遍历(方法列举)
- for … in dict 遍历key
for k in d: print(k) for k in d.keys(): print(k)
- for … in dict 遍历value
for k in d: print(d[k]) for k in d.keys(): print(d.get(k)) for v in d.value(): print(v)
- for … in dict 遍历 item in d.items():
for item in d.items(): print(item) for item in d.itmes(): print(tiem[0],item[1]) for k,v in d.items(): print(k,v) for k,_ in d.items(): print(k) for _,v in d.itmes(): print(v)
字典遍历总结
- Python3 中,keys、values、items 方法返回一个类似一个生成器的可迭代对象,不会把函数的返回结果复制到内存中 返回Dictionary view 对象,可以使用 len()、iter()、in 操作
- 字典的 entry 的动态的视图,字典变化,视图将反映出这些变化
- keys返回一个类 set对象,也就是可以看做一个set集合
- 如果values都可以hash,那么iems也可以看做是类set对象
字典遍历和移除
- 如何在遍历的时候移除元素
!错误的做法 d = dict(a=1,b=2,c='abc') for k,v in d.items(): d.pop(k) 会抛异常 while len(d): 相当于清空,不如直接clear() print(d.popitem()) while d: print(d.popitem())
正确的做法 d = dict(a=1,b=2,c='abc') keys = [] for k,v in d.items(): if isinstance(v,str): keys.append(k) for k in keys: d.pop(k) print(d)
字典的key
- key 的要求和 set 的元素要求一致 set 的元素可以就是看做key,set 可以看做dict的简化版
- hashable 可哈希才可以作为 key,可以使用 hash()测试
- d = {1:0,2.0:3,‘abc’:None,(‘hello’,‘world’,‘python’):“string”,b’abc’:‘135’}
defaultdict
- collections.defaultdict([default_factory[,…]]) 第一个参数是default_factory,缺省是None,它提供了一个初始化函数。当key不存在的时候,会调用这个工厂函数来生成key对应的value
- 构造一个字典,value是列表,为其添加随机个元素
import random d1={} for k in 'abcdef': for v in range(random.randint(1,5)): if k not in d1.keys(): d1[k] = [] d1[k].append(v) print(d1) ------------- from collections import defaultdict import random d1 = defaultdict(list) for k in 'abcdef': for v in range(random.randint(1,5)): d1[k].append(v) print(d1)
OrderedDict
- collections.OrderedDict key 并不是按照加入的顺序排列,可以使用OrderedDict记录顺序
from collections import OrderedDict import random d = {'banana:3,'apple':4,'pear':1,'orange':2} print(d) keys = list(d.keys()) random.shuffle(keys) print(leys) od = OrderedDict() for key in keys: od[key] = d[key] print(od) print(od.keys())
- 有序字典可以记录元素插入的顺序,打印的时候也是按照这个顺序输出打印
- 3.6版本的Python的字典就是记录key插入的顺序(IPython不一定有效果)
- 应用场景 假如使用字典记录了N个产品,这些产品使用ID由小到大加入到字典中
- 除了使用字典检索的遍历,有时候需要取出ID,但是希望是按照输入的顺序,因为输入顺序是有序的
- 否则还需要重新把遍历到的值排序
Python解析式、生成器
列表解析List Comprehension
- 语法 [返回值 for 元素 in 可迭代对象 if 条件]
- 使用中括号 [] , 内部是 for 循环,if 条件语句可选
- 返回一个新的列表
-
编译器会优化,不会因为简写而影响效率,反而因优化提高了效率
举例
- 获取10以内的偶数,比较执行效率
even = [] for x in range(10): if x % 2 == 0: even.append(x) -------------------------- even = [x for x in range(10) if x % 2 == 0]
FAQ
- 有这样的赋值语句 newlist = [print(i) for i in range(10)] ,请问 newlist 的元素打印出来是什么?
这样的元素打印出来是None。由于print的返回值为None,所以列表中会生成10个None
- 获取20以内的偶数,如果同时将3的倍数也打印 [i for i in range(20) if i % 2 ==0 elif i % 3 ==0] 行么?
这样做是不行的,会抛出语法错误。因为列表解析式中不允许出现else语句,想要的到问题的结果,有下面两种做法
[ i for i in range(20) if i % 2 == 0 if i % 3 == 0] [ i for i in range(20) if i % 2 == 0 and i % 3 == 0]
列表解析式进阶
[ expr for i in iterabe1 for j in iterable2 ]
等价于
ret = []
for i in iterable1:
for j in iterable2:
ret.append(expr)
- 举例
[(x,y) for x in 'abcde' for y in range(3)] [[x,y] for x in 'abcde' for y in range(3)] [{x:y} for x in 'abcde' for y in range(3)]
习题举例
- 生成一个新列表,要求新列表元素是lst相邻2项的和
numlist = [1,4,9,16,2,5,10,15] length = len(numlist) newnumlist = [ numlist[i]+numlist[i+1] for i in range(length-1)] print(newlist)
- 用列表解析式打印九九乘法表
[print('{}*{}={:>2} {}'.format(x,y,x*y, '\n' if x == y else''),end='') for x in range(1,10) for y in range(1,x+1)]
生成器表达式
- 语法 (返回值 for 元素 in 可迭代对象 if 条件)
- 列表解析式的中括号换成小括号就行了
- 返回一个生成器
-
生成器表达式是按需计算(或称惰性求值、延迟计算),需要的时候才计算值
-
可迭代对象
举例
g = ("{:04}".format(i) for i in range(1,11)) next(g) for x in g: print(x) print('~~~~~~~~~~‘) for x in g: print(x)
-
总结
延迟计算 - 返回迭代器
- 从前到后从头到尾走完一遍以后,不能回头
对比列表
g = ["{:04}".format(i) for i in range(1,11)] for x in g: print(x) print(`~~~~~~~~~~~~~~~`) for x in g: print(x)
- 总结 立即计算
- 返回的不是迭代器,返回的是可迭代对象列表
- 从前到后走完一遍后,可以重新回头迭代
和列表解析式的对比
- 计算方式 生成器表达式延迟计算,列表解析式立即计算
-
单从返回值本身来说,生成器表达式占用当前内存较小,省内存,列表解析式返回新的列表
-
单从计算时间看,生成器表达式耗时非常短,列表解析式耗时长
集合解析式
- 语法 {返回值 for 元素 in 可迭代对象 if 条件}
- 列表解析式的中括号换成大括号{}就行了
- 立即返回一个集合
-
{(x,x+1) for x in range(10)}
字典解析式
- 语法 {返回值 for 元素 in 可迭代对象 if 条件}
- 列表解析式的中括号换成大括号{}就行了
- 使用key:value 形式
- 立即返回一个字典
-
{x:(x,x+1) for x in range(10)}
总结
- Python 2 引入列表解析式
- Python 2.4 引入生成器表达式
- Python 3 引入集合、字典解析式,并迁移到了 2.7
- 一般来说,应该多应用解析式,简短、高效
- 如果一个解析式非常复杂,难以读懂,可以考虑拆解成for循环
- 生成器和迭代器是不同的对象,但都是可迭代对象
- 可迭代对象范围更大,都可以使用 for 循环遍历
相关文章推荐
- python基础知识——内置数据结构(集合)
- Python基础【数据结构:列表 | 元组 | 集合 | 字典】
- 数据结构Python实现之哈希表,字典以及集合
- Python入门:Python内置数据结构之集合set
- python 数据结构六 之 字典与集合
- python 生成器、列表/字典/集合解析式区别
- Python基础【数据结构:列表 | 元组 | 集合 | 字典】
- python基础数据结构——列表(list), 元祖(tuple), 字典(dict), 字符串(string), 集合(set) 介绍及相互转换
- 【Python】10、python内置数据结构之集合
- js数据结构与算法——集合,字典,哈希
- 关于Python数据结构中字典的心得
- Python实用技巧之列表、字典、集合中根据条件筛选数据详解
- Python数据结构基础(一)——字典(Dictionary)
- Python dict dictionaries Python 数据结构——字典
- Python基础操作 列表 字典结构 集合 循环 判断 复制操作 函数
- Python -- 如何在列表,字典,集合中筛选数据?
- Python3组合数据类型(元组、列表、集合、字典)语法
- python的各种推导式(列表推导式、字典推导式、集合推导式) 推导式comprehensions(又称解析式),是Python的一种独有特性。推导式是可以从一个数据序列构建另一个新的数据序列的结构体
- Python基础学习----数据类型,字符串,内置数据结构
- python 数据结构(字典,列表,元祖)简单操作