当前位置: 代码网 > it编程>前端脚本>Python > 从创建到去重详解Python中集合操作的完全指南

从创建到去重详解Python中集合操作的完全指南

2026年04月12日 Python 我要评论
摘要集合(set)是 python 中一种非常实用的数据结构,核心特点是无序且唯一。它最大的用途就是去重,另外还有高效的成员检测和丰富的集合运算(并集、交集、差集等)。本文我们将从零开始,系统学习集合

摘要

集合(set)是 python 中一种非常实用的数据结构,核心特点是无序且唯一。它最大的用途就是去重,另外还有高效的成员检测和丰富的集合运算(并集、交集、差集等)。本文我们将从零开始,系统学习集合的创建、基本操作、运算方法、去重应用,以及不可变的 frozenset。通过大量代码示例和图表,帮助我们快速掌握集合的各种用法

1. 前置知识点

在开始学习集合之前,我们需要先了解几个基础概念

可迭代对象:可以逐个访问元素的对象,如列表、元组、字符串等。

可变 vs 不可变

  • 可变:创建后可修改(列表、字典、集合)
  • 不可变:创建后不能修改(数字、字符串、元组)

哈希(hash):快速查找技术。不可变对象有固定哈希值,可变对象不能哈希。

2. 什么是集合(set)

2.1 集合的核心特点

集合这货啊,简单来说就是"无序且不重复"的元素容器 。它有四个核心特点,我们来一个个看:

1. 无序性 

集合里的元素没有固定顺序,不支持下标访问。也就是说,我们不能用 set[0] 这种方式来取元素。那怎么访问呢?只能通过遍历或者直接判断元素是否存在。好处是什么呢?就是我们不需要关心元素的排列顺序,只要关心"这个元素在不在集合里"就行。

s = {'a', 'b', 'c', 'd', 'e', 'f'}
print(s)  # 每次输出顺序可能不同,例如: {'c', 'a', 'f', 'd', 'b', 'e'}

2. 唯一性 

这是集合最迷人的特点——自动去重!当我们往集合里添加重复元素时,python 会自动忽略它。这个特性在实际开发中超级实用,比如我们想找出列表中不重复的元素,直接转成集合就搞定了。

s = {1, 2, 3, 2, 1, 4, 3}
print(s)  # 输出: {1, 2, 3, 4} - 自动去重了!

3. 可变性 

集合本身是可以修改的,我们可以随时添加或删除元素。不过要注意,集合里的元素必须是不可变类型,比如字符串、数字、元组等。列表和字典这种可变类型是不能作为集合元素的,因为我们没办法确定它的哈希值。

那什么是不可变类型呢?简单来说,就是"创建后不能改变"的数据类型。在 python 中:

  • 可哈希(hashable)的类型:int、float、str、bool、none、tuple(且元组内全是不可变元素)、frozenset
  • 不可哈希(unhashable)的类型:list、dict、set

为什么集合元素必须可哈希呢?因为集合底层用到了哈希表技术,它需要通过元素的哈希值来快速定位元素。如果元素是可以改变的,那它的哈希值就可能变化,集合就乱了套了。所以 python 直接规定:集合元素必须是不可变类型!

# 这些可以:
s1 = {1, 2, 3}                    # 整数
s2 = {'a', 'b', 'c'}               # 字符串
s3 = {(1, 2), (3, 4)}              # 元组(元素都是不可变的)

# 这些会报错:
s4 = {[1, 2], [3, 4]}              # ❌ typeerror: unhashable type: 'list'
s5 = {{'a': 1}}                    # ❌ typeerror: unhashable type: 'dict'
s6 = {{1, 2}}                      # ❌ typeerror: unhashable type: 'set'

4. 高效操作 

集合底层基于哈希表实现,这意味着查找、添加、删除元素的时间复杂度都是 o(1),也就是常数时间。无论集合里有100个元素还是100万个元素,操作速度都差不多。这可比列表的线性查找快多了!

2.2 集合 vs 列表 vs 元组对比 

光说集合可能不太好理解,我们来把它和列表、元组放一起对比看看 📊:

特性集合(set)列表(list)元组(tuple)
有序性❌ 无序✅ 有序✅ 有序
唯一性✅ 自动去重❌ 可以重复❌ 可以重复
可变性✅ 可变✅ 可变❌ 不可变
索引访问❌ 不支持✅ 支持✅ 支持
元素类型必须是不可变类型可以是任意类型可以是任意类型
查找效率o(1) 极快o(n) 较慢o(n) 较慢
内存占用较高较低最低

从表格能看出来,集合最适合的场景就是:需要快速查找、需要去重、需要集合运算的时候 。如果你需要保持元素顺序或者通过索引访问,那就用列表;如果你需要存储固定数据、追求极致性能,那就用元组。

3. 集合创建(set creation)

3.1 使用花括号创建

这是最直接的方式,直接用花括号把元素括起来,元素之间用逗号分隔:

# 基本创建
fruits = {"apple", "banana", "orange"}
print(fruits)  # {'banana', 'orange', 'apple'}

# 数字集合
numbers = {1, 2, 3, 4, 5}
print(numbers)  # {1, 2, 3, 4, 5}

# 混合类型(只要是不可变类型就行)
mixed = {"hello", 123, (1, 2, 3)}
print(mixed)  # {'hello', 123, (1, 2, 3)}

还有一点很方便——自动去重!如果我们写重复的元素,python 会自动帮我们去掉:

s = {1, 2, 3, 2, 1, 4, 3}
print(s)  # {1, 2, 3, 4} - 自动去重了!

不过这里有个坑:空的花括号 {} 创建的不是空集合,而是空字典! 要创建空集合必须用 set()

# ❌ 这是字典,不是集合!
empty_dict = {}
print(type(empty_dict))  # <class 'dict'>

# ✅ 这才是空集合
empty_set = set()
print(type(empty_set))  # <class 'set'>
print(empty_set)  # set()

3.2 使用 set() 函数创建

set() 函数可以创建集合,还有几个常用用法:

1. 创建空集合

empty_set = set()
print(empty_set)  # set()

2. 从列表、元组、字符串转换

这个功能超级实用!我们可以把其他可迭代对象转成集合,自动去重:

# 从列表创建(自动去重)
lst = [1, 2, 3, 2, 1, 4]
s1 = set(lst)
print(s1)  # {1, 2, 3, 4}

# 从元组创建
tup = (1, 2, 3, 2, 1)
s2 = set(tup)
print(s2)  # {1, 2, 3}

# 从字符串创建(把字符拆成集合,自动去重)
text = "hello"
s3 = set(text)
print(s3)  # {'h', 'e', 'l', 'o'} - 注意 'l' 只出现一次

3. 从集合创建(复制)

original = {1, 2, 3}
copied = set(original)
print(copied)  # {1, 2, 3}

3.3 集合推导式创建

和列表推导式类似,集合也有推导式!语法几乎一样,只是把方括号换成花括号。

# 基本语法
squares = {x**2 for x in range(1, 6)}
print(squares)  # {16, 1, 4, 9, 25}

# 带条件筛选
even_squares = {x**2 for x in range(1, 10) if x % 2 == 0}
print(even_squares)  # {16, 4, 36, 64}

# 从字符串过滤
text = "hello world"
unique_vowels = {char for char in text if char in 'aeiou'}
print(unique_vowels)  # {'e', 'o'}

# 复杂一点的条件
pairs = {(x, y) for x in range(3) for y in range(3)}
print(pairs)  # {(0, 0), (0, 1), (0, 2), (1, 0), ...}

集合推导式和列表推导式的区别:

  • 列表推导式用方括号 []
  • 集合推导式用花括号 {}
  • 集合会自动去重,列表不会

3.4 集合创建方式对比

我们来对比一下这三种创建方式:

创建方式适用场景示例
花括号 {}已知具体元素,直观简洁{1, 2, 3}
set() 函数从其他数据转换、创建空集合set([1,2,3])set()
集合推导式批量生成、有筛选逻辑{x**2 for x in range(5)}

使用建议:

  • 如果知道具体元素,用花括号最直观
  • 如果要从列表去重,用 set()
  • 如果要批量生成有规律的元素,用推导式

4. 集合基本操作

4.1 访问集合中的元素

我们前面说过,集合是无序的,所以不能用索引来访问元素。那怎么访问呢?两个办法:遍历成员检测 

1. 遍历集合

fruits = {"apple", "banana", "orange"}

# 用 for 循环遍历
for fruit in fruits:
    print(fruit)  # 每次顺序可能不同

2. 成员检测

想知道某个元素在不在集合里?用 in 操作符,超快!

fruits = {"apple", "banana", "orange"}

print("apple" in fruits)    # true
print("grape" in fruits)   # false

这就是集合最强大的地方——成员检测超级快!无论集合里有10个还是100万个元素,in 操作都是 o(1) 复杂度。

4.2 添加元素

往集合里添加元素有两种方式:

1. add() - 添加单个元素

s = {1, 2, 3}
s.add(4)
print(s)  # {1, 2, 3, 4}

# 如果添加已存在的元素,什么都不会发生(自动去重)
s.add(2)
print(s)  # {1, 2, 3, 4} - 2 已经在集合里了

2. update() - 添加多个元素

s = {1, 2, 3}
s.update([4, 5, 6])       # 从列表添加
print(s)  # {1, 2, 3, 4, 5, 6}

s.update((7, 8))          # 从元组添加
print(s)  # {1, 2, 3, 4, 5, 6, 7, 8}

s.update({9, 10})         # 从集合添加
print(s)  # {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

s.update("hello")         # 从字符串添加(每个字符)
print(s)  # {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 'h', 'e', 'l', 'o'}

4.3 删除元素

删除元素有四种方式,各有特点:

1. remove() - 删除指定元素(元素不存在会报错)

s = {1, 2, 3, 4, 5}
s.remove(3)
print(s)  # {1, 2, 4, 5}

# 如果元素不存在,会抛出 keyerror
s.remove(100)  # keyerror: 100

2. discard() - 删除指定元素(元素不存在不会报错)

s = {1, 2, 3, 4, 5}
s.discard(3)
print(s)  # {1, 2, 4, 5}

# 元素不存在也不会报错,安全感满满!
s.discard(100)  # 什么都不发生,程序继续运行

3. pop() - 随机删除并返回一个元素

s = {1, 2, 3, 4, 5}
removed = s.pop()
print(f"删除的元素: {removed}")  # 随机一个元素
print(f"剩余集合: {s}")

# 空集合调用 pop() 会报错
empty_set = set()
empty_set.pop()  # keyerror: 'pop from an empty set'

4. clear() - 清空集合

s = {1, 2, 3, 4, 5}
s.clear()
print(s)  # set() - 变成空集合了

4.4 计算集合长度

想知道集合里有多少个元素?用 len() 函数:

s = {1, 2, 3, 4, 5}
print(len(s))  # 5

# 自动去重,所以长度会变
s = {1, 1, 1, 2, 2, 3}
print(len(s))  # 3

我们来看个对比表格:

方法作用特点
add(x)添加单个元素元素已存在则忽略
update(iterable)添加多个元素可接受列表、元组、集合、字符串
remove(x)删除指定元素元素不存在会报错
discard(x)删除指定元素元素不存在不报错
pop()随机删除一个返回被删除的元素,空集合报错
clear()清空集合集合变为空集合

5. 集合运算

5.1 并集(union)

并集就是把两个集合的所有元素合并在一起,重复的只保留一个。想象一下两个班的学生,合并成一个班

运算符方式

set1 = {1, 2, 3}
set2 = {3, 4, 5}

# 用 | 运算符
result = set1 | set2
print(result)  # {1, 2, 3, 4, 5}

方法方式

set1 = {1, 2, 3}
set2 = {3, 4, 5}

# 用 union() 方法
result = set1.union(set2)
print(result)  # {1, 2, 3, 4, 5}

# union() 可以接收多个参数
result = set1.union(set2, {6, 7})
print(result)  # {1, 2, 3, 4, 5, 6, 7}

我们来看个图示:

5.2 交集(intersection)

交集就是两个集合中都有的元素。想象一下两个班都参加了某项活动的学生 

运算符方式

set1 = {1, 2, 3}
set2 = {3, 4, 5}

# 用 & 运算符
result = set1 & set2
print(result)  # {3}

方法方式

set1 = {1, 2, 3}
set2 = {3, 4, 5}

# 用 intersection() 方法
result = set1.intersection(set2)
print(result)  # {3}

# intersection() 可以接收多个参数
set3 = {3, 5, 6}
result = set1.intersection(set2, set3)
print(result)  # {3}

图示:

5.3 差集(difference)

差集就是 a 集合中有但 b 集合中没有的元素。想象一下参加了a活动但没参加b活动的学生

运算符方式

set1 = {1, 2, 3}
set2 = {3, 4, 5}

# 用 - 运算符
result = set1 - set2
print(result)  # {1, 2}

# 注意顺序:set2 - set1 结果不同
result = set2 - set1
print(result)  # {4, 5}

方法方式

set1 = {1, 2, 3}
set2 = {3, 4, 5}

# 用 difference() 方法
result = set1.difference(set2)
print(result)  # {1, 2}

图示:

5.4 对称差集(symmetric difference)

对称差集就是 a 和 b 的并集减去交集,也就是只属于其中一个集合的元素。想象一下参加了a或b活动(但不同时参加两个)的学生

运算符方式

set1 = {1, 2, 3}
set2 = {3, 4, 5}

# 用 ^ 运算符
result = set1 ^ set2
print(result)  # {1, 2, 4, 5}

方法方式

set1 = {1, 2, 3}
set2 = {3, 4, 5}

# 用 symmetric_difference() 方法
result = set1.symmetric_difference(set2)
print(result)  # {1, 2, 4, 5}

图示 :

5.5 子集和超集

子集和超集用来判断集合之间的关系:

  • 子集:a 是 b 的子集,说明 a 的所有元素 b 都有
  • 超集:a 是 b 的超集,说明 a 包含了 b 的所有元素

子集判断

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

# 用 <= 判断 a 是否是 b 的子集
print(a <= b)           # true
print(a.issubset(b))   # true

# 用 < 判断 a 是否是 b 的真子集(不是相等的情况)
print(a < b)            # true
print(a == b)          # false

超集判断

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

# 用 >= 判断 a 是否是 b 的超集
print(a >= b)           # true
print(a.issuperset(b)) # true

# 用 > 判断 a 是否是 b 的真超集
print(a > b)            # true
print(a == b)          # false

我们来看个总结表格:

运算运算符方法说明
并集|union()所有元素合并
交集&intersection()共同元素
差集-difference()a有b没有
对称差集^symmetric_difference()仅属于其中一个
子集<=issubset()a全在b里
真子集<-a全在b里且不相等
超集>=issuperset()b全在a里
真超集>-b全在a里且不相等

6. 集合方法

我们在前面已经学过增删方法(add、remove、discard、pop、clear)和运算方法(union、intersection、difference)。现在我们来聊聊那些原地修改的运算方法,也就是带 _update 后缀的这些方法 

6.1 增删方法

这部分内容我们在 第四章 已经详细介绍过了,这里简单回顾一下:

方法作用
add(x)添加单个元素
update(iterable)添加多个元素
remove(x)删除指定元素,不存在会报错
discard(x)删除指定元素,不存在不报错
pop()随机删除并返回元素
clear()清空集合
copy()复制集合

6.2 原地运算方法

这些方法会直接修改原集合,而不是返回一个新集合。它们的名字都有 _update 后缀 

1. intersection_update() - 原地求交集

s1 = {1, 2, 3, 4}
s2 = {3, 4, 5, 6}

# 求交集,并原地修改 s1
s1.intersection_update(s2)
print(s1)  # {3, 4}

2. difference_update() - 原地求差集

s1 = {1, 2, 3, 4}
s2 = {3, 4, 5, 6}

# 求差集,并原地修改 s1
s1.difference_update(s2)
print(s1)  # {1, 2}

3. symmetric_difference_update() - 原地求对称差集

s1 = {1, 2, 3, 4}
s2 = {3, 4, 5, 6}

# 求对称差集,并原地修改 s1
s1.symmetric_difference_update(s2)
print(s1)  # {1, 2, 5, 6}

4. update() - 原地求并集

s1 = {1, 2, 3}
s2 = {3, 4, 5}

# 求并集,并原地修改 s1
s1.update(s2)
print(s1)  # {1, 2, 3, 4, 5}

我们来看个对比表格:

方法作用原集合变化
union()返回并集不变
update()原地并集修改原集合
intersection()返回交集不变
intersection_update()原地交集修改原集合
difference()返回差集不变
difference_update()原地差集修改原集合
symmetric_difference()返回对称差集不变
symmetric_difference_update()原地对称差集修改原集合

使用场景:如果我们不需要保留原集合,用原地运算方法可以节省内存;如果需要保留原集合,用返回新集合的方法。

7. 集合去重应用

集合最大的用处就是去重,我们来看看几种常见场景

7.1 列表去重

lst = [1, 2, 3, 2, 1, 4, 3]
unique = list(set(lst))
print(unique)  # [1, 2, 3, 4] - 无序

# 如果需要保持顺序,用 dict.fromkeys()
# 原理:python 3.7+ 字典保持插入顺序,我们利用键的唯一性来去重
unique_ordered = list(dict.fromkeys(lst))
print(unique_ordered)  # [1, 2, 3, 4]

7.2 字符串去重

text = "hello world"
unique_chars = set(text)
print(unique_chars)  # {'h', 'e', 'l', 'o', ' ', 'w', 'r', 'd'}

# 按原顺序 - 利用字典键的唯一性和保持顺序的特性
unique_ordered = ''.join(dict.fromkeys(text))
print(unique_ordered)  # helo wrd

7.3 复杂数据去重

对于列表里的复杂数据(字典、元组等),可以用 dict.fromkeys()

data = [{'a': 1}, {'b': 2}, {'a': 1}, {'b': 2}]
unique = list(dict.fromkeys(data))
print(unique)  # [{'a': 1}, {'b': 2}]

8. frozenset:不可变集合

frozenset 就是"冻住"的集合——不可变的集合。它是 set 的兄弟,但一旦创建就不能修改

8.1 frozenset 的创建

# 从可迭代对象创建
fs1 = frozenset([1, 2, 3, 4, 5])
print(fs1)  # frozenset({1, 2, 3, 4, 5})

# 从字符串创建
fs2 = frozenset("hello")
print(fs2)  # frozenset({'h', 'e', 'l', 'o'})

# 从集合创建
fs3 = frozenset({1, 2, 3})
print(fs3)  # frozenset({1, 2, 3})

8.2 frozenset 的使用场景

1. 作为字典的键

因为 frozenset 是不可变的,所以它可以哈希,能作为字典的键:

# 用 frozenset 作为字典的键
favorites = {
    frozenset(['apple', 'banana']): '水果',
    frozenset(['chicken', 'beef']): '肉类'
}
print(favorites)  # {frozenset({'apple', 'banana'}): '水果', ...}

2. 作为集合的元素

普通的 set 是不能作为另一个 set 的元素的(因为 set 是可变的),但 frozenset 可以:

# 集合的集合 - 普通 set 不行
set_of_sets = {frozenset([1, 2]), frozenset([3, 4])}
print(set_of_sets)  # {frozenset({1, 2}), frozenset({3, 4})}

3. 需要哈希的时候

frozenset 是可哈希的,普通 set 不行:

fs = frozenset([1, 2, 3])
print(hash(fs))  # 可以哈希

s = {1, 2, 3}
# print(hash(s))  # typeerror: unhashable type: 'set'

我们来看个对比表格:

特性setfrozenset
可变性可变不可变
作为字典键❌ 不行✅ 可以
作为集合元素❌ 不行✅ 可以
哈希❌ 不可哈希✅ 可哈希

9. 总结

到这里,我们就把 python 集合的内容都学完了!我们来回顾一下

集合的核心特点:

  • 无序:不能用索引访问
  • 唯一:自动去重
  • 高效:查找、添加、删除都是 o(1)

常用的操作:

  • 创建:{}set()、集合推导式
  • 增删:add、remove、discard、pop、clear
  • 运算:并集、交集、差集、对称差集
  • 判断:子集、超集

特殊类型:frozenset:不可变集合,可以作为字典键或集合元素

以上就是从创建到去重详解python中集合操作的完全指南的详细内容,更多关于python集合操作的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com