Python数据类型-基础数据类型-集合类型 --- set
- set 对象是由具有唯一性的hashable 对象所组成的无序多项集。常见的用途包括成员检测、从序列中去除重复项以及数学中的集合类计算,例如交集、并集、差集与对称差集等等。
- 与其他多项集一样,集合也支持 x in set, len(set) 和 for x in set。作为一种无序的多项集,集合并不记录元素位置或插入顺序。相应地,集合不支持索引、切片或其他序列类的操作。
一、构造方法
1、字面量直接构造
s1 = {1, 2, 3} # 花括号 + 逗号分隔;空集合不能用 {},那是 dict| 特点 | 说明 |
|---|---|
| 语法 | 最简洁,但 不能用于空集({} 是空字典)。 |
| 元素自动去重 | {1, 1, 2} → {1, 2} |
2、内置构造函数 set(iterable=[])
s2 = set() # 空集合s3 = set([1, 2, 3, 2]) # 任意可迭代对象 → 去重s4 = set('hello') # {'h', 'e', 'l', 'o'}s5 = set(range(5)) # {0, 1, 2, 3, 4}| 形参 | 默认值 | 说明 |
|---|---|---|
| iterable | [] | 任何遵循迭代协议的对象(列表、元组、字符串、生成器等)。 |
| 返回值 | 新的 set 实例 | O(n) 复杂度,n = 去重后元素个数。 |
3、集合推导式(Set Comprehension)
s6 = {x**2 for x in range(5) if x % 2 == 0} # {0, 4, 16}- 语法与列表/字典推导式一致,自带去重。
- 执行过程:先构造临时列表 → 再转成集合(复杂度 O(n))。
4、从映射对象构造(键集合)
d = {'a': 1, 'b': 2}s7 = set(d) # {'a', 'b'} —— 取字典的 key 视图- 等价于
set(d.keys()),同样 O(n)。
5、利用 frozenset 再转 set
fs = frozenset([1, 2, 3])s8 = set(fs) # 把不可变集合变成可变集合- 当已有
frozenset且需要可变性时,可节省一次去重。
6、性能与常见误区
6.1、空集合
- 错误:empty = {} → 这是空字典!
- 正确:empty = set() 或 set().
6.2、元素必须可哈希
- 不可哈希对象(如列表、字典本身)无法加入集合
- set([[1, 2]]) → TypeError: unhashable type: ‘list’.
6.3、大列表去重最快方式
- unique = list(set(big_list))
- 时间复杂度:O(n),空间额外 O(n)。
6.4、构造器 vs 字面量
- 字面量 {1, 2, 3} 在字节码层面直接生成 BUILD_SET,
- 比 set([1, 2, 3]) 少一次列表临时对象,略快。
二、常见方法
1、set.add(elem) -> None
1.1、作用:
- 向集合 原地(in-place) 插入单个元素;若元素已存在则什么也不做,保证集合唯一性。
1.2、参数:
- elem (必需)。
- 任意 可哈希(hashable) 对象:int、str、tuple 等;
- 不可哈希对象(list、dict、set)会抛出
TypeError: unhashable type: 'xxx'。
1.3、返回值:
- 始终返回 None(因为 set 本身被修改)。
s = {1, 2}s.add(3) # s == {1, 2, 3}s.add(2) # 已存在,无变化# s.add([4, 5]) # TypeError: unhashable type: 'list'2、set.discard(elem) -> None
2.1、作用:
- 从集合 就地(in-place) 删除指定元素;如果元素不存在,静默忽略(不抛异常),保证集合唯一性不变。
2.2、参数:
- elem(必需)
- 必须是 可哈希(hashable) 对象。
- 只要 elem == existing_item 则认为匹配,不要求对象身份一致。
2.3、返回值:
- 始终返回 None;集合本身被修改。
s = {1, 2, 3}s.discard(2) # s == {1, 3}s.discard(99) # 无异常,s 仍为 {1, 3}3、set.remove(elem) -> None
3.1、作用:
- 从集合 就地(in-place) 删除 指定元素;若元素不存在,抛出
KeyError。
3.2、参数:
- elem (必需)。
- 任意 可哈希 对象,必须与集合内某个元素 相等(==) 才能匹配。
- 元素不存在时,抛出
KeyError: elem。
3.3、返回值:
- 始终返回 None(集合本身被修改)。
3.4、与相关方法对比
| 方法 | 元素不存在时行为 | 返回值 |
|---|---|---|
remove(elem) | 抛出 KeyError | None |
discard(elem) | 静默忽略 | None |
s = {1, 2, 3}s.remove(2) # s == {1, 3}# s.remove(4) # KeyError: 44、set.pop() -> element
4.1、作用:
- 就地 从集合中 移除并返回任意一个元素。
- 由于 set 无序,具体返回哪一个元素由内部哈希表实现决定,但保证 O(1) 时间复杂度。
4.2、参数:
- 无参数。调用时括号内 不允许传值。
4.3、返回值:
- 返回被移除的那个元素;若集合 为空,抛出
KeyError: 'pop from an empty set'。
4.4、与列表 pop() 区别
| 方法 | 是否可指定索引 | 是否有序 | 空时行为 |
|---|---|---|---|
list.pop(i=-1) | ✅ 可指定 | ✅ 有序 | IndexError |
set.pop() | ❌ 不可指定 | ❌ 无序 | KeyError |
s = {3, 1, 4}x = s.pop() # x 可能是 1、3 或 4print(s) # 剩余 2 个元素s.pop() # 再弹一个s.pop() # 再弹一个# s.pop() # KeyError: 'pop from an empty set'5、set.clear() -> None
5.1、作用:
- 就地(in-place) 移除集合中的所有元素,使其变为空集合
set(),但 对象身份不变(内存地址不变)。
5.2、参数:
- 无参数,调用时括号内 不得传入任何值。
5.3、返回值:
- 始终返回 None;集合本身被清空。
5.4、复杂度:
- 时间复杂度 O(n),其中 n 为集合当前元素数(需逐个置空桶位)。
- 空间复杂度 O(1),不会释放哈希表数组,仅标记空槽。
s = {1, 2, 3}old_id = id(s)s.clear()print(s) # set()print(id(s)) # 与 old_id 相同6、set.difference(*others) -> new_set
6.1、作用:
- 返回一个新的
set,内容是当前集合与 一个或多个 其他集合/可迭代对象的 差集;原集合保持不变。
6.2、参数:
- *others(任意位置参数)
- 可以是 0 个或多个 可迭代对象(set、list、tuple、dict 的键视图等)。
- 仅当元素 可哈希 时才会参与差集运算;不可哈希元素会被忽略。
6.3、返回值:
- 始终返回一个 全新的
set实例,包含只在当前集合中、而不在任何 others 中的元素。
6.4、与运算符 - 的关系:
| 形式 | 区别 |
|---|---|
a.difference(b, c) | 支持任意可迭代对象,可读性好 |
a - b - c | 只能接受 set,语法简洁 |
a = {1, 2, 3, 4}b = {3, 4, 5}
# 单参数diff = a.difference(b) # {1, 2}
# 多参数diff2 = a.difference(b, {2, 3}) # {1}
# 原集合不变print(a) # {1, 2, 3, 4}
>>> {1, 2, 3, 4} - {3, 4, 5, 6}{1, 2}7、set.union(*others) -> new_set
7.1、作用:
- 返回一个新的
set,内容 = 当前集合 并集(所有给定集合/可迭代对象的元素去重合并);原集合不变。
7.2、参数:
- *others(任意位置参数)
- 可以是 0 个或多个 可迭代对象(set、list、tuple、dict 的键视图等)。
- 只使用其中 可哈希且唯一 的元素。
7.3、返回值:
- 始终返回一个 全新的
set实例,包含所有参与对象的并集元素。
7.4、与运算符 | 的关系:
| 形式 | 区别 | 可读性 | ||
|---|---|---|---|---|
a.union(b, c) | 支持任意可迭代对象 | 可读性好 | ||
| a | b | c | 只能接受 set | 语法更简洁 |
a = {1, 2}b = {2, 3}c = [3, 4]
# 单参数u1 = a.union(b) # {1, 2, 3}
# 多参数u2 = a.union(b, c) # {1, 2, 3, 4}
# 原集合不变print(a) # {1, 2}
>>> {1, 2} | {3, 4}{1, 2, 3, 4}>>> {1, 2} | {3, 4} | {5, 6}{1, 2, 3, 4, 5, 6}8、set.intersection(*others) -> new_set
8.1、作用:
- 返回一个新的
set,内容是当前集合与 一个或多个 其他集合/可迭代对象的 交集(即所有集合共有的元素);原集合保持不变。
8.2、参数:
- *others(任意位置参数)
- 接受 0 个或多个 可迭代对象(可以是
set、list、tuple、dict.keys()等)。 - 不要求 参数类型必须是
set;只要元素 可哈希 即可参与运算。
8.3、返回值:
- 始终返回一个 全新的
set实例,包含所有输入集合共有的元素 - 若
*others为空,则返回 当前集合的浅拷贝(等同于set.copy())。
8.4、与运算符 & 的区别:
| 形式 | 支持类型 | 可读性 |
|---|---|---|
a.intersection(b, c) | 任意可迭代对象 | 高 |
a & b & c | 仅限于 set | 简洁 |
a = {1, 2, 3, 4}b = {3, 4, 5}c = [4, 3, 6]
# 两个集合i1 = a.intersection(b) # {3, 4}
# 多个可迭代对象i2 = a.intersection(b, c) # {3, 4}
# 无参数 → 返回自身拷贝i3 = a.intersection() # {1, 2, 3, 4}
# 原集合不变print(a) # {1, 2, 3, 4}
>>> {1, 2, 3} & {3, 4, 5}{3}9、set.issubset(other) -> bool
9.1、作用:
- 判断 当前集合是否为给定集合(或可迭代对象)的子集;即当前集合的所有元素都出现在对方集合中。
9.2、参数:
- other(必需)
- 可以是任意 可迭代对象(
set、list、tuple、dict.keys()等)。 - 内部会先将
other转换成临时的set,再进行子集判断。
9.3、返回值:
- True:当前集合 是 对方的子集(含 等于 的情况)。
- False:当前集合 不是 对方的子集。
9.4、与运算符 <= 的区别
| 形式 | 支持类型 | 行为 |
|---|---|---|
a.issubset(b) | 任意可迭代对象 | 可读性好 |
a <= b | 必须是 set | 语法简洁 |
a = {1, 2}b = {1, 2, 3}
a.issubset(b) # Truea.issubset([1, 2, 3]) # Trueb.issubset(a) # False10、set.issuperset(other) -> bool
10.1、作用:
- 判断当前集合是否包含给定集合(或可迭代对象)的所有元素,即当前集合是否为对方的 超集。
10.2、参数:
- other(必需)
- 可以是任意 可迭代对象(
set、list、tuple、dict.keys()等)。 - 内部先把 other 转成临时 set,再进行判断。
10.3、返回值:
- True:当前集合是对方的超集(含 等于 情况)。
- False:当前集合不是对方的超集。
10.4、与运算符 >= 的区别
| 形式 | 支持类型 | 可读性 |
|---|---|---|
a.issuperset(b) | 任意可迭代对象 | 高 |
a >= b | 必须为 set | 简洁 |
a = {1, 2, 3, 4}b = {1, 2}
a.issuperset(b) # Truea.issuperset([1, 2]) # Trueb.issuperset(a) # False三、常见函数
1、len(set)
- 获取集合的长度
2、max(set)
- 获取集合中最大的元素
3、min(set)
- 获取集合中最小的元素