教程 / Python3 / Python3 集合

Python3 集合

Python3 集合 集合(Set)是 Python 中的一种内置容器类型,用于存储多个不重复的元素。 集合具有以下特点: 元素不重复:相同的元素只会保留一份。 无序:元素没有固定的排列顺序,不支持通过索引访问。

集合(Set)是 Python 中的一种内置容器类型,用于存储多个不重复的元素。

集合具有以下特点:

  • 元素不重复:相同的元素只会保留一份。
  • 无序:元素没有固定的排列顺序,不支持通过索引访问。
  • 元素必须可哈希:可以包含整数、字符串、元组等符合条件的对象,但不能直接包含列表、字典等不可哈希对象。
  • 支持集合运算:可以进行并集、交集、差集、对称差集等操作。
  • 可以修改:普通 set 支持添加和删除元素。

集合常用于数据去重、成员判断以及多个数据集合之间的比较。

创建集合

可以使用大括号 {} 创建非空集合,元素之间使用逗号分隔,也可以使用 set() 从可迭代对象创建集合。

语法格式:

set_name = {value1, value2, value3}

set_name = set(iterable)

例如:

实例

# 使用大括号创建集合
set1 = {1, 2, 3, 4}

# 使用 set() 从列表创建集合
set2 = set([4, 5, 6, 7])

# 从字符串创建集合
set3 = set("hello")

print(sorted(set1))
print(sorted(set2))
print(sorted(set3))

执行结果:

[1, 2, 3, 4]
[4, 5, 6, 7]
['e', 'h', 'l', 'o']

可以看到,set("hello") 自动去除了重复的字母 l。

注意:创建空集合必须使用 set(),不能使用 {},因为 {} 表示空字典。

empty_set = set()  # 空集合
empty_dict = {}     # 空字典

print(type(empty_set))
print(type(empty_dict))

执行结果:

<class 'set'>
<class 'dict'>

集合自动去重

集合中的元素不会重复,因此可以利用 set() 对列表等可迭代对象进行去重。

实例

numbers = [1, 2, 2, 3, 4, 4, 5]

unique_numbers = set(numbers)

print(sorted(unique_numbers))

执行结果:

[1, 2, 3, 4, 5]

需要注意,转换为集合后,原有元素的排列顺序不会得到保证。

如果需要对列表去重并保留原有顺序,可以使用:

numbers = [3, 1, 2, 3, 2, 4]

result = list(dict.fromkeys(numbers))

print(result)

执行结果:

[3, 1, 2, 4]

上述保序去重方法要求元素可以作为字典键使用,适用于 Python 3.7 及以上版本。

集合元素的类型限制

集合中的元素必须是可哈希(Hashable)的对象。

常见的可哈希对象包括整数、浮点数、字符串,以及所有成员都可哈希的元组。

my_set = {1, 3.14, "Python", (1, 2)}

print(len(my_set))

执行结果:

4

列表、字典和普通集合通常不可哈希,不能直接作为集合元素。

my_set = {[1, 2], [3, 4]}

# TypeError: unhashable type: 'list'

如果需要将一个集合作为另一个集合的元素,可以使用不可变集合 frozenset。


集合运算

Python 集合支持数学中常见的集合运算,例如并集、交集、差集和对称差集。

假设有两个集合:

a = {1, 2, 3, 4}
b = {3, 4, 5, 6}

常见运算符如下:

运算 运算符 方法 说明
并集 | union() 两个集合中的所有元素,去除重复项
交集 & intersection() 同时属于两个集合的元素
差集 - difference() 属于第一个集合,但不属于第二个集合的元素
对称差集 ^ symmetric_difference() 只属于其中一个集合的元素

实例

a = {1, 2, 3, 4}
b = {3, 4, 5, 6}

# 并集
print("并集:", sorted(a | b))

# 交集
print("交集:", sorted(a & b))

# 差集
print("差集:", sorted(a - b))

# 对称差集
print("对称差集:", sorted(a ^ b))

执行结果:

并集: [1, 2, 3, 4, 5, 6]
交集: [3, 4]
差集: [1, 2]
对称差集: [1, 2, 5, 6]

说明:差集具有方向性,a - b 与 b - a 的结果通常不同。

除了运算符,还可以使用集合方法:

a.union(b)
a.intersection(b)
a.difference(b)
a.symmetric_difference(b)

这些方法返回新的集合,不会直接修改原集合。

集合运算符通常要求两个操作数是集合类型;对应的方法则可以根据具体方法接受列表、元组等可迭代对象。

集合推导式

与列表推导式类似,Python 也支持集合推导式(Set Comprehension),可以使用简洁的语法创建集合。

基本语法:

{expression for item in iterable if condition}

其中,if condition 是可选条件。

实例

# 生成 1 到 5 的平方集合
squares = {x * x for x in range(1, 6)}

print(sorted(squares))

# 过滤字符串中的指定字符
letters = {
    x for x in "abracadabra"
    if x not in "abc"
}

print(sorted(letters))

执行结果:

[1, 4, 9, 16, 25]
['d', 'r']

集合推导式也会自动去除重复元素。


集合的基本操作

1、添加元素

可以使用 add() 方法向集合添加一个元素。

语法格式:

s.add(x)

如果元素已经存在,集合不会发生变化,也不会报错。

实例

thisset = {"Google", "Runoob", "Taobao"}

thisset.add("Facebook")
thisset.add("Google")  # 已存在,不会重复添加

print(sorted(thisset))

执行结果:

['Facebook', 'Google', 'Runoob', 'Taobao']

如果需要一次添加多个元素,可以使用 update()。

语法格式:

s.update(iterable1, iterable2, ...)

update() 可以接收一个或多个可迭代对象,将其中的元素加入当前集合。

实例

thisset = {1, 2, 3}

# 添加列表中的元素
thisset.update([4, 5])

# 同时添加多个可迭代对象中的元素
thisset.update((6, 7), {8, 9})

print(sorted(thisset))

执行结果:

[1, 2, 3, 4, 5, 6, 7, 8, 9]

注意:如果向 update() 传入字典,添加的是字典的键,而不是值。

s = {1, 2}
s.update({"a": 10, "b": 20})

print(sorted(s, key=str))

输出结果:

[1, 2, 'a', 'b']

如果想添加字典的值,可以使用 dict.values(),前提是这些值可以作为集合元素。

2、移除元素

集合提供了 remove()、discard() 和 pop() 等删除方法。

remove() 方法

remove() 用于删除指定元素。如果元素不存在,会抛出 KeyError 异常。

语法格式:

s.remove(x)

实例

thisset = {"Google", "Runoob", "Taobao"}

thisset.remove("Taobao")

print(sorted(thisset))

# 以下操作会引发 KeyError
thisset.remove("Facebook")

执行结果:

['Google', 'Runoob']
Traceback (most recent call last):
...
KeyError: 'Facebook'

discard() 方法

discard() 同样用于删除指定元素,但如果元素不存在,不会抛出异常。

语法格式:

s.discard(x)

实例

thisset = {"Google", "Runoob", "Taobao"}

thisset.discard("Facebook")  # 不存在,不报错
thisset.discard("Taobao")

print(sorted(thisset))

执行结果:

['Google', 'Runoob']

pop() 方法

pop() 用于从集合中移除并返回一个任意元素。

语法格式:

s.pop()

实例

thisset = {"Google", "Runoob", "Taobao", "Facebook"}

# 移除一个元素
removed = thisset.pop()

print("移除的元素属于原集合:",
      removed in {"Google", "Runoob", "Taobao", "Facebook"})

print("剩余元素个数:", len(thisset))

执行结果:

移除的元素属于原集合: True
剩余元素个数: 3

注意:pop() 并不是随机抽样函数,也不是删除集合中的第一个元素。集合没有固定顺序,因此不能预测它会返回哪个元素。

如果集合为空,调用 pop() 会抛出 KeyError 异常。

删除方法对比

方法 作用 元素不存在时
remove(x) 删除指定元素 抛出 KeyError
discard(x) 删除指定元素 不报错
pop() 移除并返回任意元素 空集合会抛出 KeyError

3、计算集合元素个数

可以使用 len() 函数获取集合中的元素数量。

语法格式:

len(s)

实例

thisset = {"Google", "Runoob", "Taobao"}

print(len(thisset))

thisset.add("Google")

print(len(thisset))

执行结果:

3
3

因为集合不会保存重复元素,所以再次添加 "Google" 后,元素个数不变。

4、清空集合

可以使用 clear() 方法删除集合中的所有元素。

语法格式:

s.clear()

实例

thisset = {"Google", "Runoob", "Taobao"}

thisset.clear()

print(thisset)
print(len(thisset))

执行结果:

set()
0

这里输出的 set() 表示一个空集合。

5、判断元素是否在集合中

可以使用 in 和 not in 运算符判断元素是否属于集合。

语法格式:

x in s
x not in s

实例

thisset = {"Google", "Runoob", "Taobao"}

print("Runoob" in thisset)
print("Facebook" in thisset)
print("Facebook" not in thisset)

执行结果:

True
False
True

集合通常基于哈希表实现,因此成员判断在一般情况下具有较高效率,平均时间复杂度通常为 O(1),但最坏情况下可能退化。

6、判断子集、超集和不相交集合

除了并集、交集等运算,Python 还支持判断两个集合之间的包含关系。

常见方法如下:

方法 作用
issubset() 判断当前集合是否为指定集合的子集
issuperset() 判断当前集合是否包含指定集合的全部元素
isdisjoint() 判断两个集合是否没有公共元素

实例

a = {1, 2}
b = {1, 2, 3, 4}
c = {5, 6}

print(a.issubset(b))
print(b.issuperset(a))
print(a.isdisjoint(c))

# 也可以使用比较运算符
print(a <= b)   # 子集
print(a < b)    # 真子集
print(b >= a)   # 超集

执行结果:

True
True
True
True
True
True

<= 和 >= 允许两个集合相等;< 和 > 则分别表示真子集和真超集,要求两者不相等。

不可变集合 frozenset

除了普通集合 set,Python 还提供不可变集合 frozenset。

两者都具有元素不重复、无固定顺序等特点,但 frozenset 创建后不能添加或删除元素。

可以使用 frozenset() 创建不可变集合。

实例

a = frozenset([1, 2, 3, 3])

print(sorted(a))
print(type(a))

# frozenset 支持集合运算
b = frozenset([3, 4, 5])

print(sorted(a | b))
print(sorted(a & b))

执行结果:

[1, 2, 3]
&lt;class 'frozenset'&gt;
[1, 2, 3, 4, 5]
[3]

frozenset 不支持 add()、remove()、update() 等修改方法。

由于 frozenset 本身可以作为可哈希对象使用,因此也可以将它作为其他集合的元素。

nested_set = {
    frozenset({1, 2}),
    frozenset({3, 4})
}

print(len(nested_set))

执行结果:

2

普通的 set 不能直接作为另一个集合的元素,但 frozenset 可以。

集合使用注意事项

在使用 Python 集合时,需要注意以下几点:

  • 集合没有固定顺序:不要依赖 print(set) 的元素排列结果,也不要通过下标访问集合。
  • 元素不能重复:重复添加相同元素不会增加集合大小。
  • 元素必须可哈希:列表、字典等不可哈希对象不能直接作为集合元素。
  • set() 可以接收可迭代对象:例如字符串、列表、元组;传入字典时使用的是字典的键。
  • 集合可以遍历:可以通过 for 循环访问元素,但遍历顺序不应作为业务依据。
  • 集合不支持索引和切片:不能使用 s[0] 或 s[1:3]。
  • 注意相等性:例如 True 和 1 在集合中会被视为相等的元素,不能分别作为两个不同元素保存。

如果需要将集合中的元素按固定顺序显示,可以使用 sorted()。但如果集合包含无法相互比较的混合类型,直接排序可能引发 TypeError。

集合内置方法完整列表

以下整理了 Python 集合常用的内置方法。

方法 描述
add() 向集合添加一个元素,已存在则不做修改。
clear() 移除集合中的所有元素。
copy() 返回集合的浅拷贝。
difference() 返回差集,不修改原集合。
difference_update() 直接修改当前集合,移除同时存在于其他可迭代对象中的元素。
discard() 移除指定元素,元素不存在时不报错。
intersection() 返回交集,不修改原集合。
intersection_update() 直接修改当前集合,只保留与指定可迭代对象共有的元素。
isdisjoint() 判断两个集合是否没有公共元素。
issubset() 判断当前集合是否为指定集合的子集。
issuperset() 判断当前集合是否为指定集合的超集。
pop() 移除并返回一个任意元素,空集合会抛出 KeyError。
remove() 移除指定元素,元素不存在时抛出 KeyError。
symmetric_difference() 返回对称差集,即只存在于两个集合之一的元素。
symmetric_difference_update() 直接修改当前集合,使其只保留原集合与指定集合中非共有的元素。
union() 返回并集,不修改原集合。
update() 将一个或多个可迭代对象中的元素加入当前集合。
len() 内置函数,返回集合的元素个数。

注意:len() 是 Python 的内置函数,并非 set 对象自身的方法。

另外,以 _update() 结尾的集合方法通常直接修改原集合,并返回 None;而 union()、intersection() 等方法会返回新的集合。


总结

Python 集合主要用于存储不重复的数据,并支持高效的成员判断和常见集合运算。

在实际开发中,集合最常见的用途包括:

  • 对列表中的重复数据进行去重。
  • 判断某个元素是否存在。
  • 求两个数据集合的交集、并集和差集。
  • 比较两个集合之间的包含关系。
  • 使用 frozenset 保存不需要修改的集合。

如果需要按照索引访问数据,或者需要保留元素的插入顺序,通常应该优先考虑列表等其他数据结构;如果需要去重、集合运算或快速成员判断,则可以优先考虑集合。