1. 什么是 Set 集合?
在 Python 中,Set(集合)是一种无序、不重复元素的数据结构。它基于数学中的集合概念,主要用于成员关系测试和消除重复元素。
Set 的主要特点:
- 无序性:元素没有固定顺序
- 唯一性:自动去除重复元素
- 可变性:可以添加或删除元素(frozenset 除外)
- 可哈希性:元素必须是不可变类型
2. Set 的创建方法
2.1 使用花括号创建
# 创建包含元素的集合
fruits = {'apple', 'banana', 'orange', 'apple'}
print(fruits) # 输出: {'banana', 'orange', 'apple'}(重复的 'apple' 被自动去除)
2.2 使用 set() 函数创建
# 从列表创建集合
numbers = set([1, 2, 3, 2, 4, 1])
print(numbers) # 输出: {1, 2, 3, 4}
# 从字符串创建集合(每个字符作为元素)
chars = set('hello')
print(chars) # 输出: {'h', 'e', 'l', 'o'}
# 创建空集合(必须使用 set(),不能用 {})
empty_set = set()
print(type(empty_set)) # 输出: <class 'set'>
2.3 使用集合推导式
# 创建 1-10 的平方集合
squares = {x**2 for x in range(1, 11)}
print(squares) # 输出: {1, 4, 9, 16, 25, 36, 49, 64, 81, 100}
# 创建只包含偶数的平方集合
even_squares = {x**2 for x in range(1, 11) if x % 2 == 0}
print(even_squares) # 输出: {16, 4, 36, 100, 64}
3. Set 的基本操作
3.1 添加元素
my_set = {1, 2, 3}
# 添加单个元素
my_set.add(4)
print(my_set) # 输出: {1, 2, 3, 4}
# 添加多个元素
my_set.update([5, 6, 7])
print(my_set) # 输出: {1, 2, 3, 4, 5, 6, 7}
# 添加已存在的元素(不会有任何效果)
my_set.add(3)
print(my_set) # 输出: {1, 2, 3, 4, 5, 6, 7}
3.2 删除元素
my_set = {1, 2, 3, 4, 5}
# remove() - 删除指定元素,元素不存在会报错
my_set.remove(3)
print(my_set) # 输出: {1, 2, 4, 5}
# discard() - 删除指定元素,元素不存在不会报错
my_set.discard(2)
my_set.discard(10) # 不会报错
print(my_set) # 输出: {1, 4, 5}
# pop() - 随机删除并返回一个元素
removed = my_set.pop()
print(f"删除了: {removed}, 剩余: {my_set}")
# clear() - 清空集合
my_set.clear()
print(my_set) # 输出: set()
3.3 集合运算
A = {1, 2, 3, 4, 5}
B = {4, 5, 6, 7, 8}
# 并集
union_set = A | B # 或 A.union(B)
print(f"并集: {union_set}") # 输出: {1, 2, 3, 4, 5, 6, 7, 8}
# 交集
intersection_set = A & B # 或 A.intersection(B)
print(f"交集: {intersection_set}") # 输出: {4, 5}
# 差集
difference_set = A - B # 或 A.difference(B)
print(f"A-B差集: {difference_set}") # 输出: {1, 2, 3}
# 对称差集(只属于一个集合的元素)
symmetric_diff = A ^ B # 或 A.symmetric_difference(B)
print(f"对称差集: {symmetric_diff}") # 输出: {1, 2, 3, 6, 7, 8}
4. Set 的遍历方法
4.1 使用 for 循环直接遍历
colors = {'red', 'green', 'blue', 'yellow'}
print("直接遍历集合:")
for color in colors:
print(f"- {color}")
# 输出示例(顺序可能不同):
# - red
# - green
# - blue
# - yellow
4.2 使用 enumerate() 获取索引
fruits = {'apple', 'banana', 'orange', 'grape'}
print("带索引的遍历:")
for index, fruit in enumerate(fruits):
print(f"{index}: {fruit}")
# 输出示例(索引从0开始,但顺序不确定):
# 0: banana
# 1: orange
# 2: apple
# 3: grape
4.3 转换为列表后遍历
numbers = {10, 20, 30, 40, 50}
# 转换为列表(会丢失集合特性,但可以控制顺序)
sorted_numbers = sorted(numbers) # 按升序排序
print("按升序遍历:")
for num in sorted_numbers:
print(num)
# 输出:
# 10
# 20
# 30
# 40
# 50
4.4 遍历时修改集合(使用副本)
original_set = {1, 2, 3, 4, 5}
# 错误做法:遍历时直接修改原集合
# for num in original_set:
# if num % 2 == 0:
# original_set.remove(num) # 可能引发 RuntimeError
# 正确做法:遍历副本,修改原集合
print("删除偶数元素:")
for num in original_set.copy(): # 使用副本遍历
if num % 2 == 0:
original_set.remove(num)
print(f"删除了 {num}")
print(f"最终集合: {original_set}") # 输出: {1, 3, 5}
4.5 使用 while 循环遍历
my_set = {'a', 'b', 'c', 'd'}
set_copy = my_set.copy() # 创建副本用于遍历
print("使用 while 循环遍历:")
while set_copy:
element = set_copy.pop() # 随机弹出元素
print(f"当前元素: {element}")
# 可以对原集合进行操作
if element == 'b':
my_set.add('new_element')
print(f"原集合最终状态: {my_set}")
5. 高级遍历技巧
5.1 条件遍历
data_set = {15, 22, 8, 31, 45, 12, 7}
print("大于20的元素:")
for num in data_set:
if num > 20:
print(num)
print("\n能被3整除的元素:")
divisible_by_3 = {x for x in data_set if x % 3 == 0}
for num in divisible_by_3:
print(num)
5.2 嵌套集合遍历
# 集合的集合(需要将内层集合转换为 frozenset)
set_of_sets = {
frozenset({1, 2, 3}),
frozenset({4, 5, 6}),
frozenset({7, 8, 9})
}
print("遍历嵌套集合:")
for inner_set in set_of_sets:
print(f"子集: {set(inner_set)}")
for element in inner_set:
print(f" - {element}")
5.3 遍历集合并执行操作
# 示例:统计字符频率
text = "python programming is fun with python"
words = text.split()
unique_words = set(words)
print("单词统计:")
for word in unique_words:
count = words.count(word)
print(f"'{word}': 出现 {count} 次")
# 示例:查找共同兴趣
alice_interests = {'reading', 'coding', 'hiking', 'music'}
bob_interests = {'coding', 'music', 'gaming', 'cooking'}
print("\n共同兴趣:")
common_interests = alice_interests & bob_interests
for interest in common_interests:
print(f"- {interest}")
6. 性能考虑与最佳实践
6.1 成员测试性能
import time
# 创建大数据集
large_list = list(range(1000000))
large_set = set(large_list)
# 测试列表查找性能
target = 999999
start = time.time()
found_in_list = target in large_list
list_time = time.time() - start
# 测试集合查找性能
start = time.time()
found_in_set = target in large_set
set_time = time.time() - start
print(f"列表查找时间: {list_time:.6f} 秒")
print(f"集合查找时间: {set_time:.6f} 秒")
print(f"集合比列表快 {list_time/set_time:.1f} 倍")
6.2 遍历性能对比
import time
# 准备测试数据
test_data = set(range(1000000))
# 方法1:直接遍历
start = time.time()
total1 = 0
for num in test_data:
total1 += num
time1 = time.time() - start
# 方法2:转换为列表后遍历
start = time.time()
total2 = 0
for num in list(test_data):
total2 += num
time2 = time.time() - start
print(f"直接遍历时间: {time1:.4f} 秒")
print(f"转列表后遍历时间: {time2:.4f} 秒")
print(f"直接遍历比转列表快 {time2/time1:.2f} 倍")
6.3 最佳实践总结
- 去重优先使用集合:快速去除列表中的重复元素
- 成员测试用集合:O(1)时间复杂度 vs 列表的 O(n)
- 遍历时不要修改原集合:使用副本或推导式
- 需要顺序时先排序:使用 sorted() 获取有序列表
- 大数据集考虑性能:集合操作通常比列表更快
7. 实际应用示例
7.1 数据清洗
# 去除重复记录
raw_data = [
{'id': 1, 'name': 'Alice'},
{'id': 2, 'name': 'Bob'},
{'id': 1, 'name': 'Alice'}, # 重复记录
{'id': 3, 'name': 'Charlie'},
{'id': 2, 'name': 'Bob'}, # 重复记录
]
# 使用集合记录已处理的ID
processed_ids = set()
clean_data = []
for record in raw_data:
if record['id'] not in processed_ids:
processed_ids.add(record['id'])
clean_data.append(record)
print(f"原始数据: {len(raw_data)} 条")
print(f"清洗后数据: {len(clean_data)} 条")
7.2 标签系统
class TagSystem:
def __init__(self):
self.tags = set()
def add_tags(self, *new_tags):
"""添加多个标签"""
self.tags.update(new_tags)
print(f"添加标签: {new_tags}")
def remove_tag(self, tag):
"""移除标签"""
if tag in self.tags:
self.tags.remove(tag)
print(f"移除标签: {tag}")
else:
print(f"标签不存在: {tag}")
def find_common_tags(self, other_system):
"""查找共同标签"""
return self.tags & other_system.tags
def display_tags(self):
"""显示所有标签"""
print("当前标签:")
for i, tag in enumerate(sorted(self.tags), 1):
print(f"{i}. {tag}")
# 使用示例
system1 = TagSystem()
system1.add_tags('python', 'programming', 'tutorial')
system1.add_tags('python', 'advanced') # 重复的 'python' 不会被添加
system2 = TagSystem()
system2.add_tags('python', 'beginner', 'tutorial')
print("\n系统1标签:")
system1.display_tags()
print("\n系统2标签:")
system2.display_tags()
print("\n共同标签:")
common = system1.find_common_tags(system2)
for tag in common:
print(f"- {tag}")
7.3 权限管理系统
class PermissionManager:
def __init__(self):
self.user_permissions = {}
def grant_permissions(self, user, *permissions):
"""授予用户权限"""
if user not in self.user_permissions:
self.user_permissions[user] = set()
self.user_permissions[user].update(permissions)
def revoke_permissions(self, user, *permissions):
"""撤销用户权限"""
if user in self.user_permissions:
self.user_permissions[user].difference_update(permissions)
def check_permission(self, user, permission):
"""检查用户是否有特定权限"""
return user in self.user_permissions and permission in self.user_permissions[user]
def list_user_permissions(self, user):
"""列出用户所有权限"""
if user in self.user_permissions:
print(f"{user} 的权限:")
for perm in sorted(self.user_permissions[user]):
print(f" - {perm}")
else:
print(f"用户 {user} 没有权限")
# 使用示例
manager = PermissionManager()
# 授予权限
manager.grant_permissions('alice', 'read', 'write', 'delete')
manager.grant_permissions('bob', 'read', 'execute')
# 检查权限
print(f"Alice 有 write 权限: {manager.check_permission('alice', 'write')}")
print(f"Bob 有 delete 权限: {manager.check_permission('bob', 'delete')}")
# 列出权限
manager.list_user_permissions('alice')
manager.list_user_permissions('bob')
# 撤销权限
manager.revoke_permissions('alice', 'delete')
print(f"\n撤销后 Alice 有 delete 权限: {manager.check_permission('alice', 'delete')}")
8. 总结
Python 的 Set 集合是一个强大而高效的数据结构,特别适合处理需要唯一性和快速成员测试的场景。通过本文的学习,你应该已经掌握了:
- Set 的创建:使用花括号、set()函数和集合推导式
- 基本操作:添加、删除、集合运算等
- 多种遍历方法:for循环、enumerate、排序遍历等
- 高级技巧:条件遍历、嵌套遍历、性能优化
- 实际应用:数据清洗、标签系统、权限管理等
记住集合的核心优势:去重、快速查找、集合运算。在实际编程中,合理使用集合可以显著提高代码的效率和可读性。
最后提示:虽然集合是无序的,但从 Python 3.7 开始,字典和集合的插入顺序会被保留(作为实现细节),但不应依赖这一特性编写代码。如果需要有序集合,请使用 collections.OrderedDict 或排序后的列表。

1万+

被折叠的 条评论
为什么被折叠?



