八)集合
1、集合的概述
集合是一个无序、不重复的数据组合,只有可哈希的对象才可以被添加进集合(不可变类型:字符串、数字、元组、不可变集合)
主要的作用如下:
1)去重,把一个列表变成集合就去重了
2)关系测试,测试两组数据间的交集、并集、差集等
li=[1,2,'a','b'] s =set(li) print(s) >>{1, 2, 'a', 'b'} li2=[1,2,1,'a','a'] s=set(li2) print(s) >>{1, 2, 'a'}
2、注意的问题
集合对象是一组无序排列的可哈希的对象:集合成员可以做字典的键
li=[[1,2],'a','b']#集合的成员必须是不可变的 s =set(li) print(s) >>TypeError: unhashable type: 'list' set1 = {1, 3, 3, 4, 'mjc'} dict1 = {x:x*4 for x in set1} #集合的成员可以作字典的键 print(dict1) >>{1: 4, 'mjc': 'mjcmjcmjcmjc', 3: 12, 4: 16}
可变集合(set):可添加和删除元素,非可哈希的,不能用作字典的键,也不能做其他集合的元素
li=[1,'a','b'] s =set(li) dic={s:'123'} #注意这里是整个集合作为字典的键,因为可变,所以不能作为字典的键 >>TypeError: unhashable type: 'set'
3、集合的相关操作
1)创建集合
由于集合没有自己的语法格式,只能通过集合的工厂方法set()和frozenset()创建
s1 = set('alvin') s2= frozenset('yuan') print(s1,type(s1)) >>{'l', 'v', 'i', 'a', 'n'} <class 'set'> print(s2,type(s2)) >>frozenset({'n', 'y', 'a', 'u'}) <class 'frozenset'>
2)访问集合
由于集合本身是无序的,所以不能为集合创建索引或切片操作,只能循环遍历或使用in、not in来访问或判断集合元素。
s1 = set('alvin') print('a' in s1) >>True print('b' in s1) >>False print('alvin' in s1) >>Fale s1[1] >>TypeError: 'set' object does not support indexing for i in s1: print(i) >>v n l i a
3)更新集合
可使用以下内建方法来更新:
s.add()
s.update()
s.remove() 删除不存在的会报错
s.discard() 删除不存在的不会报错
注意只有可变集合才能更新:
s1 = frozenset('alvin') s1.add(0) >>AttributeError: 'frozenset' object has no attribute 'add' s2=set('alvin') s2.add('mm') print(s2) >>{'mm', 'l', 'n', 'a', 'i', 'v'} s2.update('HO')#添加多个元素 print(s2) >>{'mm', 'l', 'n', 'a', 'i', 'H', 'O', 'v'} s2.remove('l') print(s2) >>{'mm', 'n', 'a', 'i', 'H', 'O', 'v'}
del:删除集合本身
4、集合类型操作符
1) in ,not in
2) 集合等价与不等价(==, !=)
3)子集、超集
s=set('alvinyuan') s1=set('alvin') print('v' in s) >>True print(s1<s) >>True
4)并集
(|)union()
a = set([1, 2, 3, 4, 5]) b = set([4, 5, 6, 7, 8]) # 并集 '|' ,union() a和b去重后所有的 print(a.union(b)) print(a | b) >>{1, 2, 3, 4, 5, 6, 7, 8} >>{1, 2, 3, 4, 5, 6, 7, 8}
5)交集
(&)intersection()
a = set([1, 2, 3, 4, 5]) b = set([4, 5, 6, 7, 8]) # 交集 (&) intersection() a和b都有的 print(a.intersection(b)) print(a & b) >>{4, 5} >>{4, 5}
6)差集
(-)difference()
a = set([1, 2, 3, 4, 5]) b = set([4, 5, 6, 7, 8]) # 差集 (-) difference() a有b没有的 print(a.difference(b)) print(a - b) >>{1, 2, 3} >>{1, 2, 3}
7)对称差集
(^)symmetric_difference()
a = set([1, 2, 3, 4, 5]) b = set([4, 5, 6, 7, 8]) # 对称差集 (-) symmetric_difference()a和b的反向交集 print(a.symmetric_difference(b)) print(a ^ b) >>{1, 2, 3, 6, 7, 8} >>{1, 2, 3, 6, 7, 8}
(九)深浅拷贝
1、数字和字符串
对于字符串和数字,赋值和浅拷贝,深拷贝毫无意义,因为同时指向的是同一个内存地址
import copy ############# 数字和字符串 ############## n1 = 123 n2 = 'mjc' n1_1 = n1 # 赋值 n2_2 = n2 # 赋值 print(id(n1), id(n1_1)) >>4355288240 4355288240 print(id(n2), id(n2_2)) >>4358346040 4358346040 n1_c = copy.copy(n1) # 浅拷贝 n2_c = copy.copy(n2) # 浅拷贝 print(id(n1), id(n1_c), id(n2), id(n2_c)) >>4355288240 4355288240 4358346040 4358346040 n1_d = copy.deepcopy(n1) # 深拷贝 n2_d = copy.deepcopy(n2) # 深拷贝 print(id(n1_d), id(n1), id(n2_d), id(n2)) >>4355288240 4355288240 4358346040 4358346040
2、其他数据类型
对于字典、元祖、列表 而言,进行赋值、浅拷贝和深拷贝时,其内存地址的变化是不同的。
(1)赋值
赋值,只是创建一个变量,该变量指向原来内存地址,如
n1 = {"k1": "wu", "k2": 123, "k3": ["alex", 456]} n2 = n1
(2)浅拷贝
浅拷贝,在内存中只额外创建第一层数据
import copy n1 = {"k1": "wu", "k2": 123, "k3": ["alex", 456]} n3 = copy.copy(n1)
(3)深拷贝
深拷贝,在内存中将所有的数据重新创建一份(排除最后一层,即:python内部对字符串和数字的优化)
import copy n1 = {"k1": "wu", "k2": 123, "k3": ["alex", 456]} n4 = copy.deepcopy(n1)
列表和字典循环删除的问题
列表在循环的时候如果执行了删除操作. 索引和长度会有变化. 这种删除是不安全.
先把要删除的内容放在一个新列表中. 然后循环这个新列表. 删除老列表.
# lst = ["倚天屠龙记", "诛仙", "看见", "追风筝的人"] # clear() # lst.clear() # print(lst) # 有问题 # for i in lst: # lst.remove(i) # print(lst) # for i in lst:# for在这里的意义是记录删除的次数 # del lst[0] # 不正确 # print(lst) lst = ["倚天屠龙记", "诛仙", "看见", "追风筝的人"] # 正确 # for i in range(0, len(lst)): # lst.pop() # print(lst) # # 把要删除的东西保存在一个新列表中 # new_lst = [] # for el in lst: # new_lst.append(el) # # 循环新列表. 删除老列表 # for e in new_lst: # lst.remove(e) # print(lst)
dict在循环过程中是不允许删除的.
把要删除的键放在列表中. 循环列表删除字典
# # 生成出来的键指向的value是同一个对象. 改变其中一个的时候. 另一个也会跟着改变 # # dic = dict.fromkeys(["jay", "jj"], ["周杰伦", "林俊杰"]) # # dic['jay'].append("蔡依林") # # print(dic) # # # dic = {} # # dic.fromkeys(["葫芦娃", "蛇精"], ["冯提莫", "陈一发"]) # # print(dic) # 什么都不打印. # # # dic = {"韩哥":"发图不留种", "奎峰":"斗图小皇帝", "徐阳":"开车不留情"} # # for item in dic: # 直接循环迭代的时候拿到的是key # # if item == '奎峰': # # dic.pop(item) # dictionary changed size during iteration # # # 循环删除的案例 # # dic = {"韩哥":"发图不留种", "奎峰":"斗图小皇帝", "徐阳":"开车不留情"} # # lst = ['奎峰'] # # for el in lst: # 循环list # # dic.pop(el) # 删除的是dict中的元素 # # print(dic) # # lst = ["发图哥", "谁困. 下午就往他那发图", "轰炸"] # print(type(lst)) # list # tu1 = tuple(lst) # tuple # print(tu1) # () # print(type(tu1)) # tuple # lst1 = list(tu1) # list # print(lst1) # [] # # # 能转换成False的数据类型有哪些 # # 0, '', [], (), {}, None, set(), False dic = {"a":'老A', 'b':"王宝强", 'c':"蓉姐", 'd':'百合姐'} for k in dic: if k == 'b' or k == 'c': dic.pop(k) # dictionary changed size during iteration