注意:
1、集合和字典都没有下标,所以,也就不支持索引下标的相关操作。
2、创建一个空集合比较特殊,有固定写法:set1 = set( )
3、列表有序,集合无序;列表内成员可重复,集合内成员不可重复。
4、集合的增加:add( )只能添加一个值,且该值必须是不可变的数据类型(数字、元组、字符串),update( )可以一个或多个值,这些值必须是可迭代的(比如,那5个)。
5、集合的删除:pop( )删除结果中的第一个。remove、discard都是删除指定成员。区别是:如果要删除的成员不在集合里,则remove会报错,而discard不会报错。
一、集合——set
用{ }表示集合。需要注意的是,空集合的定义比较特殊,具体如下:
格式:变量名=set( )
例如:定义一个空集合和非空集合。
set1 = set() # 创建一个空集合
print(set1)
结果:
set()
set1 = {1, "hello", 4, 6, 3} #定义一个非空集合
print(set1)
结果: #因为集合无序,所以结果不唯一
{1, 3, 4, 6, 'hello'}
或{'hello', 1, 3, 4, 6}
或{1, 'hello', 3, 4, 6}
......
1、查看集合所有方法
print(dir(set))
结果:
['__and__', '__class__', '__contains__', '__delattr__',
'__dir__', '__doc__', '__eq__', '__format__', '__ge__',
'__getattribute__', '__gt__', '__hash__', '__iand__',
'__init__', '__init_subclass__', '__ior__', '__isub__',
'__iter__', '__ixor__', '__le__', '__len__', '__lt__',
'__ne__', '__new__', '__or__', '__rand__', '__reduce__',
'__reduce_ex__', '__repr__', '__ror__', '__rsub__',
'__rxor__', '__setattr__', '__sizeof__', '__str__',
'__sub__', '__subclasshook__', '__xor__',
'add', 'clear', 'copy', 'difference', 'difference_update',
'discard', 'intersection', 'intersection_update',
'isdisjoint', 'issubset', 'issuperset',
'pop', 'remove', 'symmetric_difference',
'symmetric_difference_update', 'union', 'update']
二、集合常用的方法
1、增加——add( )、update( )
集合无序,所有不能使用下标,因此添加进去,位置也是随机的,无法指定,最终打印出来的集合顺序也是多种多样的。需要注意的是,因为集合中的成员是不重复的,所以,如果添加的元素在集合中已存在,那么再添加就没效果。
(1)add(值)——只能添加一个元素,且该元素必须是不可变的数据类型(也叫可哈希数据类型),比如:数值型、元组、字符串。否则报错。
(2)update(值)——可以添加一个或者多个元素,但添加的元素必须是可迭代的数据类型,(什么叫可迭代的?能用for循环遍历的就是可迭代,比如:那五个非数值型数据。)——也就是说除了单纯的数字,其它都能添加。但是,数字其实也是可以添加的,只要把数字外面裹上[ ]或( )或{ },相当于变相的把数字变成了列表、元组、集合,那么这样也就能添加进去了。
添加进去之后需要注意的是:
(1)如果是字符串,那么结果中就会把字符串进行拆分,比如:
set1 = {"苹果", 2}
set1.update("西瓜") # 添加一个元素,该元素是一个字符串
print(set1)
结果:
{'苹果', 2, '瓜', '西'}
(2)如果是列表、元组、集合,结果就不会拆分。比如:
set1 = {"苹果", 2}
set1.update((99, 456, "hello")) # 添加一个元素,该元素是一个元组,该元组有3个成员
print(set1)
结果:
{2, 99, 'hello', 456, '苹果'}
(3)如果是字典,结果加的只是键。
set1 = {"苹果", 2}
set1.update({"name": "张三", "age": 18}) # 添加字典,只放键
print(set1)
结果:
{'age', 2, 'name', '苹果'}
例如:用add添加。
set1 = {"橘子", 3}
set1.add(3.14) # 添加数值型
print(set1)
结果:
{3.14, '橘子', 3} # 加什么 出什么
set1 = {"橘子", 3}
set1.add("西瓜") # 添加字符串
print(set1)
结果:
{'西瓜', 3, '橘子'}
set1 = {"橘子", 3}
set1.add((1,)) # 添加一个元组,只有一个成员
set1.add((8, 9)) # 添加一个元组,有2个成员
print(set1)
结果:
{(8, 9), '橘子', 3, (1,)}
set1 = {"橘子", 3}
set1.add((8, 9), (99,)) # 添加2个元组,即:添加两个元素
print(set1)
结果: # 所以,add只能添加一个元素
TypeError: add() takes exactly one argument (2 given)
注意区分添加的是一个元素还是多个元素。例如:
set1.add((8, 9)) —— 一个元组,也就是一个元素,它有2个成员
set1.add((8, 9), (99,))——两个元组,也就是两个元素——所以add会报错
例如:add只能添加不可变的数据类型,比如:数值型、元组、字符串。添加其它就报错。
set1 = {"橘子", 3}
set1.add(["大米"]) # 添加列表
print(set1)
结果:
set1.add(["大米"])
TypeError: unhashable type: 'list'
"""
翻译过来就是:不可哈希的类型:列表
什么叫可哈希?
一个对象的哈希值如果在其生命周期内绝不改变,就被称为可哈希。
也就是不可变数据类型,比如:数值型、字符串、元组。
不可哈希:即:可变数据类型,比如:列表、字典、集合。
它们在改变值的同时,却没有改变id,无法由id定位值的唯一性。
"""
# 添加集合也是一样,报错
set1 = {"橘子", 3}
set1.add({"小麦"})
print(set1)
结果:
set1.add({"小麦"})
TypeError: unhashable type: 'set'
例如:用update添加。
set1 = {"苹果", 2}
set1.update("西瓜") # 添加了一个元素 (添加的是一个字符串)
print(set1)
结果:
{'苹果', 2, '瓜', '西'} # 被拆分
set1 = {"苹果", 2}
set1.update("西瓜", "cd") # 添加了两个元素 (添加的是2个字符串)
print(set1)
结果:
{2, '瓜', '苹果', '西', 'c', 'd'}
set1 = {"苹果", 2}
set1.update("西瓜", "cd", ["asd", 100]) # 添加多个元素,分别是字符串、列表
print(set1)
结果:
{'d', 2, 100, 'c', '西', '瓜', '苹果', 'asd'}
# 可以看到,字符串成员被拆分了,而列表成员没被拆分,比如100,没被拆成1,0,0
set1 = {"苹果", 2}
set1.update({99, 100}) # 添加一个元素,集合,也没拆分
print(set1)
结果:
{99, 2, '苹果', 100}
set1 = {"苹果", 2}
set1.update({"name": "张三", "age": 18}) # 添加字典,只放键
print(set1)
结果:
{'age', 2, 'name', '苹果'}
例如:添加数值型报错。
set1 = {"苹果", 2}
set1.update(99)
print(set1)
结果:
set1.update(99)
TypeError: 'int' object is not iterable
# 也就是说,数值型是不可迭代对象,也就意味着,update只能添加可迭代对象。
所谓可迭代就是指能用for遍历的对象。比如那5个:列表、元组、字典、集合、字符串。
技巧:把数值型变成列表、元组、集合中的任何一个,就能顺利添加了。
set1 = {"苹果", 2}
set1.update((99,)) # 法1 :把它变成元组
print(set1) # !!变成元组时候要注意,如果是单成员,末尾要加逗号
结果:
{'苹果', 2, 99}
set1 = {"苹果", 2}
set1.update({99}) # 法2 :把它变成集合
print(set1)
结果:
{99, 2, '苹果'}
set1 = {"苹果", 2}
set1.update([99]) # 法3 :把它变成列表
print(set1)
结果:
{2, 99, '苹果'}
例如:利用update分别添加一个成员和多个成员。
set1 = {"苹果", 2}
set1.update((99, 456, "hello")) # 添加一个元素,该元素是一个元组,该元组有3个成员
print(set1)
结果:
{2, 99, 'hello', 456, '苹果'}
set1 = {"苹果", 2}
set1.update((99, 456, "hello"), (1,), [100]) # 添加3个元素,该元素是:2个元组、一个列表
print(set1)
结果:
{1, 2, 99, 100, 456, '苹果', 'hello'}
2、删除——pop( )、remove(值)、discard(值)、clear( )
(1)pop( )——删除结果中的第一个成员,不常用。使用pop时候,在删除之前输出一下原集合,可以发现,pop删除的是当前打印出来的第一个元素。
set1 = {1, 5, 2}
print(set1) # 删除前先打印下set1
set1.pop() #再用pop删除一个值
print(set1)
结果:
{1, 2, 5}
{2, 5} # 可以看见第一个元素被删掉了
(2)remove和discard都是删除指定成员。区别是:如果要删除的成员不在集合里,则remove会报错,而discard不会报错。
set1 = {1, 5, 2}
set1.remove(5) # 5在集合里
print(set1)
结果:
{1, 2}
set1 = {1, 5, 2}
set1.remove(4) # 4不在集合里,报错
print(set1)
结果:
KeyError: 4
set1 = {1, 5, 2}
set1.discard(4) # 4不在集合里,但是不会报错
print(set1)
结果:
{1, 2, 5}
set1 = {1, 5, 2}
set1.discard(5)
print(set1)
结果:
{1, 2}
(3)clear( )——清空集合。
set1 = {1, 5, 2}
set1.clear()
print(set1)
结果:
set()
3、公共方法
set1 = {1, 5, 2}
print(len(set1))
print(max(set1))
print(min(set1))
print(5 in set1)
print(5 not in set1)
结果:
3
5
1
True
False
4、用for 遍历
遍历出来的结果,可能跟原来定义集合的时候顺序不一样,这是正常的,因为集合无序,所以遍历的时候就没有所谓的顺序可言,但不管怎样,最终结果都是把所有成员都遍历一遍。
set1 = {1, 5, 2}
for i in set1:
print(i)
结果:
1
2
5
例如:定义一个空集合变量,通过input函数,任意输入3个整数,以此来做为集合的成员,最后求成员中的最大值和最小值,以及遍历该集合。
set1 = set()
a = 0
while a < 3:
set1.add(int(input("请输入一个数:")))
a += 1
print("该集合最大值是:%d" % max(set1))
print("该集合最小值是:%d" % min(set1))
for i in set1:
print(i)
结果:
请输入一个数:-20
请输入一个数:5
请输入一个数:100
该集合最大值是:100
该集合最小值是:-20
100
-20
5
三、集合的运算
主要有:并集、差集、交集、异或(或叫对称差集)。——只适用于集合与集合之间
1、并集—— | 用一个竖杠表示
表示把所有的元素合并到一起组成新的集合,此时,新集合称为这多个集合的并集。
set1 = {1, 2, 3, 4}
set2 = {3, 4, 5, 6}
print(set1 | set2)
结果:
{1, 2, 3, 4, 5, 6}
set1 = {1, 2, 3, 4}
set2 = {3, 4, 5, 6}
set3 = {3, 0, 7}
print(set1 | set2 | set3)
结果:
{0, 1, 2, 3, 4, 5, 6, 7}
延申:
集合里还有一个方法,也是求并集——union( ),但与上面不同的是,union不仅可以求集合与集合之间的并集,也可以求集合与可迭代对象之间的并集。比如:可以求集合与集合/列表/元组/字典/字符串之间的并集。而 | 只能求集合与集合之间的并集,求集合与其它数据类型之间的并集就会报错。
union( )语法格式:
set1.union(set2, set3...,list1...,tuple1...,dict1...,str1....)
其中,union前面,即set1的位置,必须是一个集合变量,union后面就可以随意了,可以是集合、列表、元组、字典、字符串中的一个或多个。
例如:
set1 = {1, 2, 3, 4}
set2 = {3, 4, 5, 6}
list1 = [90, 100]
tuple1 = (80, 100)
str1 = "加油"
dict1 = {"name": "张三", "age": 18} # 对于字典,只取键
print(set2.union(set1, list1, tuple1, dict1, str1))
结果:
{1, 2, 3, 4, 5, 6, 100, '油', 'age', 'name', 80, '加', 90}
set1 = {1, 2, 3, 4}
list1 = [90, 100]
print(set1 | list1)
结果:
print(set1 | list1)
TypeError: unsupported operand type(s) for |: 'set' and 'list'
# 同理,和元组、字典也都会报错。
#如果是数字就报错 所以,union()只适用于集合与可迭代对象之间求并集
set1 = {1, 2, 3, 4}
b = 123
print(set1.union(b))
结果:
print(set1.union(b))
TypeError: 'int' object is not iterable
2、差集—— - 用减号表示
set1 = {1, 2, 3, 4}
set2 = {3, 4, 5, 6}
print(set1 - set2)
结果:
{1, 2}
3、交集—— & ——取共有部分。
set1 = {1, 2, 3, 4}
set2 = {3, 4, 5, 6}
print(set1 & set2)
结果:
{3, 4}
4、异或—— ^ ——取非共有部分
set1 = {1, 2, 3, 4}
set2 = {3, 4, 5, 6}
print(set1 ^ set2)
结果:
{1, 2, 5, 6}
四、强制类型转换
例如:将字符串转为集合。
a = set("ababc")
print(a)
print(type(a))
结果:
{'a', 'b', 'c'} 或{'c', 'b', 'a'}......
<class 'set'>
需要注意的是:强制转换时,必须是可迭代的对象才能转为集合,否则报错,例如,数值型就不能转。 一般常把字符串强转为集合,其它的比如像列表、元组、字典在编写时候pycharm就会给出友情提示。
a = set(123) # 数字转为集合——报错
print(a)
print(type(a)) # 因为它不是可迭代对象
结果:
a = set(123)
TypeError: 'int' object is not iterable
a = set("123") # 字符串“123”
print(a)
print(type(a))
结果:
{'3', '2', '1'}
<class 'set'>
#列表、元组、字典也能强制转化成集合,但平时不这么写,
#因为在写时候pycharm就会给出提示,让直接写成集合没必要转化。
a = set([123]) 或 a = set((123,))
print(a)
print(type(a))
结果:
{123}
<class 'set'>
a = set({"name": "张三", "age": 18}) # 字典强制转化为集合,只加键
# a = set([123])
print(a)
print(type(a))
结果:
{'age', 'name'}
<class 'set'>
五、集合和列表的区别
1、列表有序,集合无序。
列表中所有的成员是有序的,对应的就是可以用下标来进行增删改查。而集合中所有成员无序,(也就意味着每次输出时,成员之间的位置不固定),所以就不能使用下标。
2、列表内的成员可重复,集合内的成员不可重复。
同一个列表中成员的值可以重复,而同一个集合内成员的值不可重复。即:集合里的值都是唯一的。
例如:定义时候,写了多个1多个3,但print时候,也仅会出来一个。即:结果自动去重复。也就是说在print(集合名)的时候会自动删除成员间重复的元素。
set1 = {1, 1, 3, "hello", 4, 6, 3}
print(set1) # 定义时候,尽管写了多个1多个3,但print时候,也仅会出来一个
结果:
{1, 'hello', 3, 4, 6}
六、字典——dict
(1)用{ }定义一个字典。
(2)字典用来存放“键值对”的数据,键和值用冒号分隔,多个键值对之间用逗号分隔。
(3)同一个字典内,键不能重复。
(4)定义一个空字典:变量名={ }
例如:定义两个字典变量,要求,一个空,一个非空。
dict1 = {} # 定义一个空字典
print(dict1)
结果:
{}
dict2 = {"name": "张三", "age": 18} # 定义一个非空字典
print(dict2)
结果:
{'name': '张三', 'age': 18}
字典和集合的区别:集合里只有值,字典里面是键值对。
七、字典的常用操作——增删改查、公共方法
字典里的所有方法:
print(dir(dict))
结果:
['__class__', '__contains__', '__delattr__',
'__delitem__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__',
'__getitem__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__iter__', '__le__', '__len__',
'__lt__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__',
'__setitem__', '__sizeof__', '__str__', '__subclasshook__',
'clear', 'copy', 'fromkeys', 'get', 'items', 'keys',
'pop', 'popitem', 'setdefault', 'update', 'values']
1、增加 或 修改——增加键值对、修改值
语法格式:
(1)字典[键] = 值——如果键存在,那就是修改值,如果键不存在,那就是增加新的键值对。
(2)字典的合并
字典1.update(字典2)——把字典2 加到字典1的后面。如果有相同的键,那么字典1里的值将会被替换。注意:用update()添加的只能是字典,也就是只能添加的是键值对,否则都报错。
dict2 = {"name": "张三", "age": 18}
dict2["name"] = "李四" # 将name键对应的值"张三" 改为 "李四"
dict2["sex"] = "男" # 新增一个键值对,键为sex,值为男
print(dict2)
结果:
{'name': '李四', 'age': 18, 'sex': '男'}
# 合并两个字典
dict1 = {"name": "张三", "age": 18}
dict2 = {"sex": "男", "name": "李四"} # 有相同的键“name” 此时会进行替换
dict1.update(dict2) # 把字典2的数据,加到字典1的后面
print(dict1)
结果:
{'name': '李四', 'age': 18, 'sex': '男'} # 合并后,李四替换了张三
例如:添加的不是键值对,就会报错。
dict1 = {"name": "张三", "age": 18}
list1 = ["hello"]
dict1.update(list1) # 添加列表,报错
print(dict1)
结果:
dict1.update(list1)
ValueError: dictionary update sequence element #0 has length 5; 2 is required
dict1 = {"name": "张三", "age": 18}
a = "123"
dict1.update(a) # 添加字符串,报错
print(dict1)
结果;
dict1.update(a)
ValueError: dictionary update sequence element #0 has length 1; 2 is required
2、删除——pop( )、popitem( )
格式:
pop("键")——根据键,删指定键值对。
popitem( )——删除字典中的最后一个键值对。
clear( )——清空字典
例如:删除name键,以及清空字典。
dict2 = {"name": "张三", "age": 18}
dict2.pop("name") # 删除name键,对应的值也将被删除
print(dict2)
结果:
{'age': 18}
dict2 = {"name": "张三", "age": 18, "sex": "男"}
print(dict2)
dict2.popitem() # 删最后一个键值对
print(dict2)
结果:
{'name': '张三', 'age': 18, 'sex': '男'}
{'name': '张三', 'age': 18}
dict2 = {"name": "张三", "age": 18}
dict2.clear() # 清空字典
print(dict2)
结果:
{}
3、查——字典名["键"]、get( )
(1)字典名["键"] 和get( "键")都可以获取键对应的值。——获取某个值。
例如:获取name键对应的值。
# 法1
dict2 = {"name": "张三", "age": 18}
a = dict2["name"] #把键对应的值赋值给变量a
print(a)
# 或者直接写成:print(dict2["name"])
结果:
张三
#法2
dict2 = {"name": "张三", "age": 18}
print(dict2.get("name")) # 使用get()
结果:
张三
(2)字典名.keys( )——获取所有键,结果放到一个列表里。
(3)字典名.values( )——获取所有的值,结果也是放到一个列表里。
dict1 = {"name": "张三", "age": 18}
print(dict1.keys())
结果:
dict_keys(['name', 'age'])
dict1 = {"name": "张三", "age": 18}
print(dict1.values())
结果:
dict_values(['张三', 18])
4、for循环遍历字典——for a,b 字典名.items( )
for n in 字典名:——只遍历键
for n in 字典名.values():——只遍历值
for a, b in 字典名.items():——遍历键值对,将键和值分别赋给两个变量
例如:只遍历键、只遍历值。
dict1 = {"name": "张三", "age": 22}
for n in dict1:
print(n) # 只遍历键
结果:
name
age
dict1 = {"name": "张三", "age": 22}
for n in dict1.values():
print(n) # 只遍历值
结果:
张三
22
例如:可以通过字典["键"]来获取键对应的值。
dict1 = {"name": "张三", "age": 22}
for n in dict1:
print(n, dict1[n]) # 字典名[键]可以取键的值
结果:
name 张三
age 22
改进:上面虽然能获取键对应的值了,但毕竟不是在for循环中直接获取的,怎么能直接在for循环中就输出值呢?利用items( )方法来获取字典中的键值对,此时,得到的结果就是一个包含了键和值的元组。
dict1 = {"name": "张三", "age": 22}
for n in dict1.items(): # 利用items()来获取键值对
print(n)
结果:
('name', '张三') # 得到的结果是一个包含了键和值的元组
('age', 22) # 即:此时n就是一个包含了两个成员的元组,
#一个成员是键,一个成员是值
再次改进:将元组进行拆包——去掉括号。
dict1 = {"name": "张三", "age": 22}
for n in dict1.items():
a, b = n # 对元组进行拆包
print(a, b)
结果:
name 张三 # 此时括号没有了
age 22
将代码进行优化:此时,a就是键,b就是键对应的值。
dict1 = {"name": "张三", "age": 22}
for a, b in dict1.items():
print(a, b)
结果:
name 张三
age 22
例如:求值为22时,对应的键名。
dict1 = {"name": "张三", "age": 22}
for n in dict1: # 遍历键
if dict1[n] == 22: # 字典名[键]--取键的值
print(n)
结果:
age