集合

  • 集合是一个无序、可变、不允许数据重复的容器

定义

1
v1 = {11,22,33,"alex"}
  • 无序:无法通过索引取值
  • 可变:可以添加和删除元素
1
2
3
4
5
v1 = {11,22,33,"alex"}

v1.add(55)

print(v1) # {33,11,44,22}不会再添加重复的元素
  • 使用集合的情况
    • 想要维护一大堆不重复的数据时,就可以用它。
    • 例如:做爬虫去网上找图片的链接,为了避免链接重复,可以选择用集合去存储连接地址
  • 注意:定义空集合时
1
2
3
4
5
# 只能用
v = set() # 这样是定义一个空字典

# 而不能用
v = {}
  • 补充:
1
2
3
4
5
6
7
8
9
10
v1 = []
v11 = list

v2 = ()
v22 = tuple()

v3 = set()

v4 = {} # 空字典
v44 = diet()

独有功能

添加元素

1
2
3
4
5
6
7
8
data = {"刘嘉玲","关之琳","王祖贤"}
data.add("郑裕玲")
print(data) # {'郑裕玲', '关之琳', '王祖贤', '刘嘉玲'}

data = set()
data.add("周杰伦")
data.add("林俊杰")
print(data) # {'周杰伦', '林俊杰'}

删除元素

1
2
3
data = {"刘嘉玲","关之琳","王祖贤","张曼玉","李若彤"}
data.discard("关之琳")
print(data) # 由于集合的无序性和独立性,所以集合里面删除就删除该元素的唯一一个

交集

1
2
3
4
5
6
s1 = {"刘能","赵四","皮长山"}
s2 = {"刘科长","冯乡长","皮长山"}
s3 = s1 & s2 # 方式一:取两个集合的交集
s4 = s1.intersection(s2) # 方式二: 取两个集合的交集
print(s3,s4) # {'皮长山'} {'皮长山'}
取交集的时候原变量不变,只是创建了新的变量

并集

1
2
3
4
5
6
7
8
s1 = {"刘能","赵四","皮长山"}
s2 = {"刘科长","冯乡长","皮长山"}
s4 = s1.union(s2)

s3 = s1 | s2

print(s3,s4)
# {'冯乡长', '皮长山', '赵四', '刘能', '刘科长'} {'冯乡长', '皮长山', '赵四', '刘能', '刘科长'}

差集

1
2
3
4
5
6
7
8
9
10
s1 = {"刘能","赵四","皮长山"}
s2 = {"刘科长","冯乡长","皮长山"}
s4 = s1.difference(s2) # 方式二:差集,s1中有且s2中没有的值
s3 = s1 - s2 # 方式一:差集,s1中有且s2中没有的值 这种减法更简便
print(s3,s4) # {'刘能', '赵四'} {'刘能', '赵四'}

s5 = s2 - s1 # 方式二:差集,s2中有且s1中没有的值{}
s6 = s2.difference(s1) # 方式一:差集,s2中有且s1中没有的值
print(s5,s6) # {'冯乡长', '刘科长'} {'冯乡长', '刘科长'}

公共功能

减 计算差集

1
2
3
4
5
6
7
s1 = {"刘能","赵四","皮长山"}
s2 = {"刘科长","冯乡长","皮长山"}

s3 = s1 - s2
s4 = s2 -s1
print(s3) # {'赵四', '刘能'}
print(s4) # {'冯乡长', '刘科长'}

& 计算交集

1
2
3
4
s1 = {"刘能","赵四","皮长山"}
s2 = {"刘科长","冯乡长","皮长山"}
s3 = s1 & s2
print(s3) # {'皮长山'}

| 计算并集

1
2
3
4
5
s1 = {"刘能","赵四","皮长山"}
s2 = {"刘科长","冯乡长","皮长山"}
s3 = s1 | s2
print(s3)

长度

1
2
3
v = {"刘能","赵四","尼古拉斯"}
data = len(v)
print(data) # 3

for循环

1
2
3
4
5
6
7
v = {"刘能","赵四","尼古拉斯"}
for item in v:
print(item)
# 刘能
# 赵四
# 尼古拉斯
# 注意集合是无序的它不能用索引取值,只能用for循环一一取值

转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
其他类型如果想要转换为集合类型,可以通过set进行转换,并且如果数据有重复自动剔除。
提示:str/list/tuple/dict都可以转换为集合

字符串转集合
v1 = "武沛齐"
v2 = set(v1)
print(v2) # {'齐', '沛', '武'}

列表转集合
v1 = [11,22,33,11,3,99,22]
v2 = set(v1)
print(v2) # {33, 3, 99, 11, 22}

元组转集合
v1 = (11,22,3,11)
v2 = set(v1)
print(v2) # {3, 11, 22}

提示:这其实也是去重的一个手段

data = {11,22,33,3,99}
v1 = list(data)
v2 = tuple(data)
print(v1) # [33, 99, 3, 22, 11]
print(v2) # (33, 99, 3, 22, 11)

其他

集合的存储原理

  • 当创建一个集合的时候,python内部会创建一个表(哈希表)
    集合是无序的原因:就是程序经过哈希函数运算后的排列无序

image-20240314212700278

集合的元素必须可哈希

  • 因存储原理,集合的元素必须是可哈希的值,即:内部通过哈希函数把值转换成一个数字。

image-20240314212710325

  • 目前可哈希的数据类型:int、bool、str、tuple,而list、set是不可哈希的。
  • 总结:集合的元素只能是int、bool、str、tuple

转换成功

image-20240314212743199

  • 列表转换为集合是可行的

转换失败

image-20240314212759096

  • 但是列表里面的元素如果有集合的话,那么转换成集合就会转换失败

查找速度特别快

  • 因存储原理特殊,集合的查找效率非常高(数据量大了才明显)。

  • 低:

1
2
3
4
5
6
7
8
9
10
11
12
user_list = ["武沛齐","alex","李璐"]
if "alex" in user_list:
print("在")
else:
print("不在")

user_tuple = {"武沛齐","alex","李璐"}
if "alex" in user_tuple:
print("在")
else:
print("不在")

  • 元组和列表中判断一个元素在不在里面的查找步骤差不多一样
  • 效率高:是因为其组成原理
1
2
3
4
5
user_set = {"武沛齐","alex","李璐"}
if "alex" in user_set:
print("在")
else:
print("不在")
  • 如果想要判断元素在不在里面,且元素无重复,尽量用集合,效率高

对比和嵌套

image-20240314212852603

image-20240314212903254

  • 列表是可以放在元组中的,但是如果列表放在元组里面,然后该元组做为集合的元素放在集合里面的话就不行了。
    注意:集合中要求元素必须可哈希
            集合中元素的元素也必须是可哈希,否则会报错
    
  • 注意:由于True和False本质上存储的是1和0,而集合又不允许重复,所以在整数0、1和False、True出现在集合中会有如下现象

练习题

  • 写代码实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
v1 = {"alex","武sir","肖大"}
v2 = []

# 循环提示用户输入,如果输入值在v1中存在
# 则追加到v2中,如果v1中不存在,则添加到v1中。(如果输入N或n则停止循环)

while True:
name = input("请输入姓名:")
if name in v1:
v2.append()
else:
v1.add(name)

v1 = {"alex","武sir","肖大"}
v2 = []

# 循环提示用户输入,如果输入值在v1中存在
# 则追加到v2中,如果v1中不存在,则添加到v1中。(如果输入N或n则停止循环)

while True:
name = input("请输入姓名(N/n退出):")
if name.upper() == "N":
break
else:
pass
if name in v1:
v2.append()
else:
v1.add(name)
  • 下面哪些值不能做集合的元素
1
2
3
4
5
6
“” 可以
0 可以
[11,22,33] 不可以
[] 不可以
(123) 可以
{1,2,3} 不可以
  • 模拟用户信息输入程序,已录入则不再创建
1
2
3
4
5
6
7
8
9
10
user_info_set = set()

while True:
name = input("请输入姓名:")
age = input("请输入年龄:")
item = (name,age,)
if item in user_info_set:
print("该用户已录入")
else:
user_info_set.add(item)
  • 给你个列表去重
1
2
3
v = [11,22,11,22,44455]
data = set(v) # {11,22,44455}
result = list(data) # [11,22,44455]

None类型

  • Python的数据类型中有一个特殊的值None,意味着这个值啥都不是 或 表示空。相当于其他语言中 null 作用一样。
    在一定程度上可以帮助我们去节省内存。例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
v1 = None
v2 = None
...
v1

#以后在创建一个值,在不知道等于多少或者之后要改成另一个值,可以先把它写成None

v3 = []
v4 = []
...
v3 = [11,22,33,44]
v4 = [111,22,43]

# 注意:暂不要考虑python内部的缓存和驻留机制。
  • 目前所有转换为布尔值为False的值有:
1
2
3
4
5
6
0
""
[] or list()
() or tuple()
set()
None

字典

  • 字典是 无序、键不重复 且 元素只能是键值对的可变的 个容器
1
data = {"k1":1, "k2":2}
  • 容器:元素必须是键值对 “k1”:1是一个键值对 “k2”:2也是一个键值对 冒号前面是键,后面是值,用逗号隔开,用花括号括起来
  • 键不重复,重复则会被覆盖
1
2
data = {"k1":1,"k1":2}
print(data) # {'k1': 2}
  • 无序(在python3.6+字典就是有序了,之前的字典都是无序。)
1
2
data = {"k1":1, "k2":2}
print(data) # {'k1': 1, 'k2': 2}

定义

1
2
3
4
5
6
7
8
9
10
11
12
13
v1 = {}
v2 = dict()

data = {"k1":1, "k2":2}


info = {
"age":12,
"status":True,
"name":"wupeiqi",
"hobby":['篮球','足球']
}

  • 字典中对键值的要求:
    • 键:必须可哈希。目前位置学到的可哈希的类型:int/bool/str/tuple;不可哈希的类型:list/set/dict。
    • 值:任意类型。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
data_dict ={
"武沛齐":29,
True:5,
123:5,
(11,22,33):["alex","eric"]
}



# 不合法
v1 = {
[1,2,3]:'周杰伦',
"age":18
}

v2 = {
{1,2,3}:"哈哈哈",
"name":"alex"
}

v3 = {
{"k1":123,"k2":456}:"呵呵呵",
"age":999
}

data_dict = {
1:29,
True:5
}
print(data_dict)# {1: 5}
# 注意:这种情况与集合的情况一样
  • 一般用到字典的情况
  • 当我们想要表示一组固定信息时,用字典可以更加的直观,例如:
1
2
3
4
5
6
# 用户列表
user_list = [("alex","123"),("admin","666")]

#用户列表
user_list = [{"name":"alex","pwd":"123"},{"name":"eric","pwd":"12"}]
注意:由于字典的键值特性,可以标名数据的用途,如:账号、密码等,会更加直观,更加规范。

独有功能

获取单个值

  • 可以使用get获取值

    • 当使用get获取键对应的值时,当键存在则返回对应的值
    • 当键不存在就会返回None
  • 示例1:

1
2
3
4
5
6
7
8
9
10
#示例
info = {"age":12 , "status":True , "name":"武沛齐"}

data1 = info.get("name")
print(data1) # 输出:武沛齐

data2 = info.get("age")
print(data) # 输出:12

data = info.get("email") # 键不存在,默认返回 None
  • 根据示例1,可以对其进行判断:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
if data == None:
print("此键不存在")
else:
print(data)


# 可以进行if操作
#简化后
if data :
print(data)
else:
print("此键不存在")



# 可以先判断字典存不存在该键
if "emali" in info:
data = info.get("email")
print(data)
else:
print("此键不存在")
data = info.get("hobby",123)
print(data)
#输出:123 先去查找字典里是否有该键,若有则反回字典里面的值,
#如果字典我该

获取所有键

  • 使用keys()可以获取一个字典的所以键
  • 注意:在Python2中字典.keys()直接获取到的是列表,而Python3中返回的是高仿列表,这个高仿列表可以被循环显示。Python3的性质可以节省内存
  • 例如:
1
2
3
4
info = {"age":12, "status":True, "name":"wupeiqi","email":"xx@live.com"}
data = info.keys()
print(data)
# dict_keys(['age', 'status', 'name', 'email'])
  • 高仿列表可以被for循环
1
2
3
info = {"age":12, "status":True, "name":"wupeiqi","email":"xx@live.com"}
for ele in info.keys():
print(ele)
  • 还可以利用高仿列表判断某个键是否有在列表中
1
2
3
4
if "age" in info.keys():
print("age是字典的键")
else:
print("age不是")

获取所有值

  • 使用values()可以获取字典里面所有的值
  • 注意:与keys()一样,在Python2中字典.values()直接获取到的是列表,而Python3中返回的是高仿列表,这个高仿列表可以被循环显示

  • 例如:

1
2
3
4
info = {"age":12, "status":True, "name":"wupeiqi","email":"xx@live.com"}
data = info.values()
print(data)
# dict_values([12, True, 'wupeiqi', 'xx@live.com'])
  • 对高仿列表值进行循环和判断某个值是否在该字典里面
1
2
3
4
5
6
7
info = {"age":12, "status":True, "name":"wupeiqi","email":"xx@live.com"}
for val in info.values():
print(val)
if 12 in info.values():
print("12是字典的值")
else:
print("12不是字典的值")

获取所有的键值

  • 可以使用items()字典里面所有的键值,但是获取的值会变成一对的元组,这些元组对被伪列表包裹

  • 例如:

1
2
3
4
5
info = {"age":12, "status":True, "name":"wupeiqi","email":"xx@live.com"}
data = info.items()
print(data)
# dict_items([('age', 12), ('status', True), ('name', 'wupeiqi'), ('email', 'xx@live.com')])

  • 可以对该伪列表进行循环操作
1
2
3
4
5
6
7
8
9
info = {"age":12, "status":True, "name":"wupeiqi","email":"xx@live.com"}
for ite in info.items():
print(ite[0],ite[1])
"""
age 12
status True
name wupeiqi
email xx@live.com
"""
  • 还可以进行如下循环的输出
1
2
3
4
5
6
7
8
9
info = {"age":12, "status":True, "name":"wupeiqi","email":"xx@live.com"}
for key,value in info.items():
print(key,value)
"""
age 12
status True
name wupeiqi
email xx@live.com
"""
  • 也可以利用这个伪列表判断键值对是否在字典里面
1
2
3
4
5
6
7
info = {"age":12, "status":True, "name":"wupeiqi","email":"xx@live.com"}
data = info.items()

if ('age',12) in data:
print("在")
else:
print("不在")

设置值

  • 可以使用setdefult()在字典里面设置值
    • 当键不存在,就在字典里面添加这个键值对
    • 当键存在,那就不会添加,也不会更改键对应的值
  • 例如:
1
2
3
4
5
data = {"name":"武沛齐","email":"xxx@live.com"}
data.setdefault("age",18)
data.setdefault("name","alex")
print(data)
# {'name': '武沛齐', 'email': 'xxx@live.com', 'age': 18}

更新字典值对

  • 使用update()更新字典里面的键值对
    • 如果该键值对不存在,就添加该键值对
    • 如果该键存在,则更新该键对应的值
  • 例如:
1
2
3
4
info = {"age":12,"status":True}
info.update({"age":14,"name":"武沛齐"})
print(info)
# {'age': 14, 'status': True, 'name': '武沛齐'}

移除指定键值对

  • 使用pop()可以移除指定键值对,并返回移除的值
  • 例如:
1
2
3
4
5
6
info = {"age":12,"status":True,"name":"武沛齐"}

data = info.pop("age")

print(info) # {'status': True, 'name': '武沛齐'}
print(data) # 12

按顺序移除(后进先出)

  • 使用popitem()可以按顺序移除键值对,从后往前移出,并返回这个键值对,用元组进行返回

    • Python3.6后,popitem移除最后的值
    • Python3.6前,popitem随机删除
  • 例如:

1
2
3
4
5
6
info = {"age":12,"status":True,"name":"武沛齐"}
data = info.popitem()
print(info)
print(data)
# {'age': 12, 'status': True}
# ('name', '武沛齐')