集合是一种无序、元素唯一的容器类型。
无序,是指从集合中取出元素的顺序,与定义集合时存入的顺序不一定一致。
集合分两种,分别是:
可变集合使用花括号{}包裹,不同数据项之间用,做分隔。
# 定义非空可变集合
s1 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
s2 = {'你好', '远方', '太原'}
s3 = {100, '优秀', True, 50.89, None}
print(type(s1), s1) # <class 'set'> {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
print(type(s2), s2) # <class 'set'> {'远方', '太原', '你好'}
print(type(s3), s3) # <class 'set'> {None, True, 50.89, 100, '优秀'}
# 定义可变空集合
s4 = set()
print(type(s4), s4) # <class 'set'> set()
需要注意的是,不能直接写{}来定义空集合,因为直接写{}定义的是空字典。
s5 = {}
print(type(s5), s5) # <class 'dict'> {}
不可变集合需要借助内置的<font style="color:#080808;background-color:#ffffff;">frozenset</font>函数。
frozenset()函数接收的参数,可以是任意可迭代对象,但返回的一定是【不可变集合】。
# 定义非空不可变集合
s6 = frozenset({10, 20, 30})
s7 = frozenset({'你好', 'Python', '远方', '太原'})
s8 = frozenset({100, '好好学习', True, 12.4, None})
print(type(s6), s6) # <class 'frozenset'> frozenset({10, 20, 30})
print(type(s7), s7) # <class 'frozenset'> frozenset({'太原', '你好', 'Python', '远方'})
print(type(s8), s8) # <class 'frozenset'> frozenset({'好好学习', True, None, 100, 12.4})
# frozenset 可接收可迭代对象,返回不可变集合
s9 = frozenset([1, 2, 3])
s10 = frozenset((10, 20, 30))
s11 = frozenset('python')
print(type(s9), s9) # <class 'frozenset'> frozenset({1, 2, 3})
print(type(s10), s10) # <class 'frozenset'> frozenset({10, 20, 30})
print(type(s11), s11) # <class 'frozenset'> frozenset({'y', 'p', 'n', 't', 'h', 'o'})
# 定义不可变空集合
s12 = frozenset()
print(type(s12), s12) # <class 'frozenset'> frozenset()
集合中不能嵌套可变集合,但可以嵌套不可变集合。(为什么?——只有“不可变”的东西,才能安全的放进集合里。)
s1 = {10, 20, 30}
s2 = frozenset({100, 200, 300})
l1 = [1000, 2000, 3000]
t1 = ('a', 'b', 'c')
# ss1 = {11, 22, 33, s1} # 报错:TypeError: unhashable type: 'set'
ss2 = {11, 22, 33, s2}
print(type(ss2), ss2) # <class 'set'> {33, frozenset({200, 100, 300}), 11, 22}
# ss3 = {11, 22, 33, l1} # 报错:TypeError: unhashable type: 'list'
ss4 = {11, 22, 33, t1}
print(type(ss4), ss4) # <class 'set'> {33, 11, ('a', 'b', 'c'), 22}
方式1:使用集合.add(元素),向集合中添加元素,无返回值。
s1 = {1, 2, 3}
s1.add(4)
print(s1) # {1, 2, 3, 4}
方式2:使用集合.update(元素),向集合中批量添加元素(接收可迭代对象),无返回值。update 方法向集合中添加元素必须传递可迭代对象,例如:列表、元组、集合等。
s1 = {1, 2, 3}
s1.update([4, 5])
s1.update((6, 7))
s1.update({8, 9})
s1.update(range(10, 12))
s1.update('abc')
print(s1) # {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 'a', 'b', 'c'}
方式1:使用集合.remove(元素),从集合中移除指定元素(若元素不存在,会报错),无返回值。
s1 = {0, 1, 2, 3, 5, 6, 7, 8, 9}
s1.remove(5)
print(s1) # {0, 1, 2, 3, 6, 7, 8, 9}
方式2:使用集合.discard(元素),从集合中移除指定元素(元素若不存在,不会报错),无返回值。
s1 = {0, 1, 2, 3, 5, 6, 7, 8, 9}
s1.discard(5)
print(s1) #
方式3:使用集合.pop(),从集合中移除任意一个元素,返回值:移除的那个元素。
s1 = {0, 1, 2, 3, 5, 6, 7, 8, 9}
result = s1.pop()
print(result, s1) # 0 {1, 2, 3, 5, 6, 7, 8, 9}
result = s1.pop()
print(result, s1) # 1 {2, 3, 5, 6, 7, 8, 9}
方式4:使用集合.clear(),清空集合,无返回值。
s1 = {0, 1, 2, 3, 5, 6, 7, 8, 9}
result = s1.clear()
print(result, s1) # None set()
注意:集合没有下标,也不支持 replace 方法,所以集合没有专门用于“改”的方法,但可以使用 remove + add 的组合,来达到“修改”的效果。
s1 = {0, 1, 2, 3, 6, 5}
print(s1) # {0, 1, 2, 3, 5, 6}
s1.remove(5)
s1.add(4)
print(s1) # {0, 1, 2, 3, 4, 6}
注意:由于集合没有下标,也不支持切片,所以集合不具备按位置访问的能力。虽然不能通过下标读取元素,但可以使用【成员运算符】来判断:某个元素是否在集合中,成员运算符我们会在后续详讲。
s1 = {1, 2, 3}
result = 4 in s1
print(result) # False
result = 2 in s1
print(result) # True
集合常用方法有如下几个:(下表中s1和s2代表两个内容不同的集合)
| 方法名 | 功能说明 | 返回值 |
|---|---|---|
| s1.difference(s2) | 找出s1中不同于s2的元素 | s1和s2都不变,返回新集合 |
| s1.difference_update(s2) | 从s1中删除s2中存在的元素 | s1被修改,s2不变,无返回值 |
| s1.union(s2) | 合并两个集合s1和s2 | s1和s2都不变,返回新集合 |
| s1.issubset | 判断s1是否为s2的子集 | 返回布尔值 |
| s1.issuperset(s2) | 判断s1是否为s2的超集 | 返回布尔值 |
| s1.isdisjoint(s2) | 判断s1和s2是否没有交集 | 返回布尔值 |
使用s1.difference(s2),找出s1中不同于s2的元素,s1和s2都不变,返回新集合。
s1 = {'a', 'b', 'c', 'd'}
s2 = {'c', 'd', 'e', 'f', 'g'}
result = s1.difference(s2)
print(result) # {'b', 'a'}
使用s1.difference_update(s2),从s1中删除s2中存在的元素,s1被修改,s2不变,无返回值。
s1 = {'a', 'b', 'c', 'd'}
s2 = {'c', 'd', 'e', 'f', 'g'}
s1.difference_update(s2)
print(s1) # {'b', 'a'}
print(s2) # {'f', 'd', 'g', 'c', 'e'}
使用s1.union(s2),合并两个集合s1和s2,s1和s2都不变,返回新集合。
s1 = {'a', 'b', 'c', 'd'}
s2 = {'c', 'd', 'e', 'f', 'g'}
result = s1.union(s2)
print(s1) # {'b', 'd', 'a', 'c'}
print(s2) # {'e', 'd', 'g', 'f', 'c'}
print(result) # {'e', 'b', 'd', 'g', 'f', 'a', 'c'}
使用s1.issubset,判断s1是否为s2的子集,返回布尔值。如果集合s1的所有元素都在s2中,那就返回True,否则返回False。
s1 = {'a', 'b', 'c', 'd'}
s2 = {'c', 'd', 'e', 'f', 'g'}
s3 = {'c', 'd', 'e'}
print(s3.issubset(s1)) # False
print(s3.issubset(s2)) # True
使用s1.issuperset(s2),判断s1是否为s2的超集,返回布尔值。如果集合s1中包含了集合s2的所有元素,那就返回True,否则返回False。
s1 = {'a', 'b', 'c', 'd'}
s2 = {'c', 'd', 'e', 'f', 'g'}
s3 = {'c', 'd', 'e'}
print(s1.issuperset(s3)) # False
print(s2.issuperset(s3)) # True
使用s1.isdisjoint(s2),判断s1和s2是否没有交集,返回布尔值。如果没有交集,返回True;只要有一个公共元素,就返回False。
s1 = {'a', 'b', 'c', 'd'}
s2 = {'c', 'd', 'e', 'f', 'g'}
s3 = {'c', 'd', 'e'}
s4 = {'x', 'y', 'z'}
print(s1.isdisjoint(s3)) # False
print(s2.isdisjoint(s4)) # True
s1 = {10, 20, 30, 40, 50, 60}
s2 = {40, 50, 60, 70, 80, 90}
result = s1 | s2
print(result, type(result), len(result)) # {70, 40, 10, 80, 50, 20, 90, 60, 30} <class 'set'> 9
s1 = {10, 20, 30, 40, 50, 60}
s2 = {40, 50, 60, 70, 80, 90}
result = s1 & s2
print(result, type(result), len(result)) # {40, 50, 60} <class 'set'> 3
s1 = {10, 20, 30, 40, 50, 60}
s2 = {40, 50, 60, 70, 80, 90}
result = s1 - s2
print(result, type(result), len(result)) # {10, 20, 30} <class 'set'> 3
result = s2 - s1
print(result, type(result), len(result)) # {80, 90, 70} <class 'set'> 3
s1 = {10, 20, 30, 40, 50, 60}
s2 = {40, 50, 60, 70, 80, 90}
result1 = s1 ^ s2
print(result1, type(result1), len(result1)) # {70, 10, 80, 20, 90, 30} <class 'set'> 6
由于集合不支持下标,所以集合不能使用 while 循环遍历。可以使用 for 循环遍历。
s1 = {1, 2, 3, 4, 5, 6}
for item in s1:
print(item)
一句话总结:集合是可以去重的数据容器,当只关心元素是否存在,而不在乎顺序时,首选集合。