在 Python 里,集合是个很有特点的容器类型。咱们先从最基本的说起,集合里的元素有两个关键特性:独一无二和没有顺序。这意味着你没法像列表那样用下标(比如 s [0])访问元素,而且无论你往集合里塞多少重复的东西,它最终只会留一个。
一、创建集合的三种方式
创建集合有三种常用方法,咱们一个个看:
第一种是直接用大括号{},比如{"FishC"},这样创建的集合里就只有一个元素 "FishC"。
第二种是集合推导式,像{s for s in "FishC"}。这里会遍历字符串 "FishC" 的每个字符,最终得到的集合是{'F', 'i', 's', 'h', 'C'}(顺序不确定,因为集合无序)。
第三种是用set()函数,set("FishC")的效果和上面的集合推导式一样,也是把字符串拆成单个字符,组成集合。
不过要注意,空集合不能用{}创建(那会被当成空字典),得用set()。
二、集合的基础操作
检查元素是否存在
想知道某个元素在不在集合里,用in或not in就行。比如:
s = set("FishC")
print('i' in s) # 输出True,因为's'里有'i'
print('x' not in s) # 输出True,'x'不在集合里
列表去重
集合的 “去重” 能力很实用。如果列表里有重复元素,转成集合再转回去,就能轻松去重:
nums = [1, 2, 2, 3, 3, 3]
unique_nums = list(set(nums)) # 结果是[1,2,3](顺序可能不同)
浅拷贝
用.copy()可以复制一个集合,修改原集合不会影响拷贝的集合:
a = {1, 2}
b = a.copy()
a.add(3)
print(b) # 输出{1,2},不受a的影响
三、集合关系检测
是否无交集(isdisjoint)
a.isdisjoint(b)判断 a 和 b 有没有共同元素,没有的话返回 True。比如:
s1 = set("FishC") # 包含'F','i','s','h','C'
s2 = set("Python") # 包含'P','y','t','h','o','n'
print(s1.isdisjoint(s2)) # 输出False,因为两者都有'h'
子集与超集
a.issubset(b)检查 a 是不是 b 的子集(a 的元素都在 b 里);a.issuperset(b)检查 a 是不是 b 的超集(b 的元素都在 a 里)。比如:
a = {1, 2}
b = {1, 2, 3}
print(a.issubset(b)) # True,a是b的子集
print(b.issuperset(a)) # True,b是a的超集
也可以用运算符:a <= b等价于a.issubset(b),a >= b等价于a.issuperset(b)。如果是 “真子集”(a 是 b 的子集且 a≠b),用a < b;“真超集” 用a > b。
四、集合运算
并集、交集、差集、对称差集
- 并集(合并所有元素):a.union(b)或a | b
- 交集(共同元素):a.intersection(b)或a & b
- 差集(a 有而 b 没有的元素):a.difference(b)或a - b
- 对称差集(a 和 b 独有的元素,排除共同的):a.symmetric_difference(b)或a ^ b
注意:方法的参数可以是任何可迭代对象(比如列表、字符串),但运算符两边必须都是集合。比如:
a = {1, 2, 3}
b = {3, 4, 5}
# 方法示例(参数用列表也可以)
print(a.union([4,5,6])) # {1,2,3,4,5,6}
# 运算符示例(必须是集合)
print(a | b) # {1,2,3,4,5}
五、不可变集合(frozenset)
普通集合是可变的(能增删元素),但frozenset(a)会创建一个不可变集合,不能修改,所以能嵌套到其他集合里。比如:
fs = frozenset({1, 2})
s = {fs, 3} # 合法,frozenset可以嵌套
# 下面的代码会报错,因为普通集合不能嵌套
# s = {{1,2}, 3} # 报错:unhashable type: 'set'
六、修改集合的方法
增加元素
- s.update(*others):把可迭代对象的每个元素添加进去。比如s.update("ab")会加 'a' 和 'b'。
- s.add(x):把 x 整个作为元素添加。比如s.add("ab")会加字符串 "ab"。
删除元素
- s.remove(x):删除 x,若 x 不存在则报错。
- s.discard(x):删除 x,x 不存在也不报错(静默处理)。
- s.pop():随机弹出一个元素(因为集合无序)。
- s.clear():清空集合。
示例:
s = {1, 2}
s.update([3, 4]) # s变成{1,2,3,4}
s.add(5) # s变成{1,2,3,4,5}
s.remove(3) # s变成{1,2,4,5}
s.discard(10) # 啥也不做,不报错
print(s.pop()) # 随机输出一个元素,比如1
s.clear() # s变成空集合
七、哈希与集合元素的要求
集合的元素必须是 “可哈希” 的。简单说,不可变对象(如整数、字符串、元组)是可哈希的,可变对象(如列表、集合)是不可哈希的。因为集合用 “散列表” 存储,靠哈希值快速查找,所以只有可哈希的才能当元素。
比如,列表不能当集合元素,但元组可以:
# 下面的代码会报错
# s = {[1,2], 3} # 报错:unhashable type: 'list'
# 正确写法
s = {(1,2), 3} # 合法,元组可哈希
八、为什么列表转集合效率高?
列表查找元素时,得一个个遍历,效率低;而集合用 “散列表” 存储,通过哈希值直接定位元素位置,虽然占的空间多,但查找、添加、删除的速度快很多,这就是 “以空间换时间”。所以处理大量数据去重或判断存在性时,用集合比列表更高效。