Python快速学习——第5章:集合

6 阅读7分钟

第五章:集合

5.1 什么是集合?

集合就像 一个没有重复元素的魔法袋子,里面的元素没有顺序,每个元素都是唯一的,而且集合会自动去除重复的元素。

# 创建集合
fruits = {"苹果", "香蕉", "橙子", "苹果"}  # 重复的"苹果"会被自动去除
numbers = {1, 2, 3, 4, 5, 3, 2, 1}      # 重复的数字会被去除

5.2 集合的创建方式

集合可以用多种方式创建:

# 直接使用花括号
fruits = {"苹果", "香蕉", "橙子"}
​
# 使用set()函数从其他序列创建
numbers = set([1, 2, 3, 4, 5])        # 从列表创建
chars = set("hello")                   # 从字符串创建,得到:{'h', 'e', 'l', 'o'}
mixed = set([1, "hello", 3.14, True])  # 可以包含不同类型的元素# 创建空集合
empty_set = set()
# 注意:empty_set = {} 创建的是空字典,不是空集合# 使用集合推导式
squares = {x**2 for x in range(1, 6)}  # {1, 4, 9, 16, 25}

5.3 集合的基本特性

5.3.1 无序性

集合中的元素没有固定的顺序:

fruits = {"苹果", "香蕉", "橙子"}
print(fruits)  # 每次输出的顺序可能不同

5.3.2 唯一性

集合会自动去除重复元素:

numbers = {1, 2, 2, 3, 3, 3, 4, 4, 4, 4}
print(numbers)  # {1, 2, 3, 4} - 重复元素被自动去除

5.3.3 不可索引

由于集合是无序的,不能通过索引访问元素:

fruits = {"苹果", "香蕉", "橙子"}
# print(fruits[0])  # 这会报错!集合不支持索引

5.4 集合的基本操作

5.4.1 集合长度

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

fruits = {"苹果", "香蕉", "橙子"}
print(len(fruits))  # 3

5.4.2 检查元素是否存在

使用 in 关键字检查元素是否在集合中:

fruits = {"苹果", "香蕉", "橙子"}
print("苹果" in fruits)  # True
print("葡萄" in fruits)  # False

5.4.3 集合的遍历

虽然集合是无序的,但可以遍历所有元素:

fruits = {"苹果", "香蕉", "橙子"}

# 直接遍历元素
for fruit in fruits:
    print(f"水果:{fruit}")

# 使用enumerate获取序号(但序号不代表固定位置)
for i, fruit in enumerate(fruits):
    print(f"第{i}个水果是:{fruit}")

5.5 集合的常用方法

5.5.1 添加元素

fruits = {"苹果", "香蕉"}
​
# add() - 添加单个元素
fruits.add("橙子")
print(fruits)  # {'苹果', '香蕉', '橙子'}# update() - 添加多个元素
fruits.update(["葡萄", "芒果"])
print(fruits)  # 添加了葡萄和芒果# 添加已存在的元素不会有任何效果
fruits.add("苹果")
print(fruits)  # 集合不变

5.5.2 删除元素

fruits = {"苹果", "香蕉", "橙子", "葡萄"}
​
# remove() - 删除指定元素,如果元素不存在则报错
fruits.remove("香蕉")
print(fruits)  # 删除了香蕉# discard() - 删除指定元素,如果元素不存在也不报错
fruits.discard("西瓜")  # 西瓜不存在,但不报错# pop() - 随机删除并返回一个元素(因为集合无序)
removed_fruit = fruits.pop()
print(f"删除了:{removed_fruit}")
print(fruits)
​
# clear() - 清空集合
fruits.clear()
print(fruits)  # set()

5.6 集合的数学运算

集合支持多种数学运算,这是集合最强大的特性之一。

5.6.1 并集

包含两个集合中所有的元素:

A = {1, 2, 3}
B = {3, 4, 5}

# 使用 | 运算符
print(A | B)  # {1, 2, 3, 4, 5}

# 使用 union() 方法
print(A.union(B))  # {1, 2, 3, 4, 5}

5.6.2 交集

包含两个集合中共有的元素:

A = {1, 2, 3}
B = {3, 4, 5}
​
# 使用 & 运算符
print(A & B)  # {3}# 使用 intersection() 方法
print(A.intersection(B))  # {3}

5.6.3 差集

包含在第一个集合中但不在第二个集合中的元素:

A = {1, 2, 3}
B = {3, 4, 5}
​
# 使用 - 运算符
print(A - B)  # {1, 2}# 使用 difference() 方法
print(A.difference(B))  # {1, 2}

5.6.4 对称差集

包含两个集合中不重复的元素(即只属于其中一个集合,不属于交集的元素):

A = {1, 2, 3}
B = {3, 4, 5}
​
# 使用 ^ 运算符
print(A ^ B)  # {1, 2, 4, 5}# 使用 symmetric_difference() 方法
print(A.symmetric_difference(B))  # {1, 2, 4, 5}

5.7 集合的关系运算

5.7.1 子集和超集

A = {1, 2, 3}
B = {1, 2}

# 子集检查
print(B <= A)  # True - B是A的子集
print(B.issubset(A))  # True

# 超集检查
print(A >= B)  # True - A是B的超集
print(A.issuperset(B))  # True

# 真子集/真超集
print(B < A)   # True - B是A的真子集
print(A > B)   # True - A是B的真超集

5.7.2 不相交集合

检查两个集合是否没有共同元素:

A = {1, 2, 3}
B = {4, 5, 6}
C = {3, 4, 5}

print(A.isdisjoint(B))  # True - A和B没有共同元素
print(A.isdisjoint(C))  # False - A和C有共同元素3

5.8 集合的更新操作

除了返回新集合的操作外,还有直接修改原集合的操作:

A = {1, 2, 3}
B = {3, 4, 5}

# update() - 用并集更新原集合
A.update(B)
print(A)  # {1, 2, 3, 4, 5}

A = {1, 2, 3}
B = {3, 4, 5}

# intersection_update() - 用交集更新原集合
A.intersection_update(B)
print(A)  # {3}

A = {1, 2, 3}
B = {3, 4, 5}

# difference_update() - 用差集更新原集合
A.difference_update(B)
print(A)  # {1, 2}

A = {1, 2, 3}
B = {3, 4, 5}

# symmetric_difference_update() - 用对称差集更新原集合
A.symmetric_difference_update(B)
print(A)  # {1, 2, 4, 5}

5.9 冻结集合

冻结集合是不可变的集合,因此可以作为字典的键或另一个集合的元素:

# 创建冻结集合
frozen = frozenset([1, 2, 3, 4, 5])
print(frozen)  # frozenset({1, 2, 3, 4, 5})

# 冻结集合不可修改
# frozen.add(6)  # 会报错!

# 冻结集合可以作为字典的键
dict_with_frozenset = {frozen: "这是一个冻结集合"}
print(dict_with_frozenset)  # {frozenset({1, 2, 3, 4, 5}): '这是一个冻结集合'}

# 冻结集合也可以作为普通集合的元素
set_with_frozenset = {frozen, frozenset([6, 7, 8])}
print(set_with_frozenset)

5.10 集合的应用场景

5.10.1 数据去重

集合最常见的用途是去除序列中的重复元素:

# 列表去重
numbers = [1, 2, 2, 3, 3, 4, 5, 5]
unique_numbers = list(set(numbers))
print(unique_numbers)  # [1, 2, 3, 4, 5](顺序可能不同)

# 字符串去重
text = "hello world"
unique_chars = ''.join(set(text))
print(unique_chars)  # 类似 'helo wrd'(顺序可能不同)

5.10.2 成员测试

由于集合的成员测试效率很高(基于哈希表),适合用于快速检查元素是否存在:

# 大量数据成员测试时,集合比列表快很多
valid_users = {"user1", "user2", "user3", "user4", "user5"}
user_input = "user3"

if user_input in valid_users:
    print("有效用户")
else:
    print("无效用户")

5.10.3 数学运算

处理数学中的集合运算:

# 选课系统示例
math_students = {"Alice", "Bob", "Charlie"}
physics_students = {"Bob", "David", "Eve"}

# 同时选了两门课的学生
both = math_students & physics_students
print(both)  # {'Bob'}

# 所有选课的学生
all_students = math_students | physics_students
print(all_students)  # {'Alice', 'Bob', 'Charlie', 'David', 'Eve'}

# 只选了一门课的学生
only_one = math_students ^ physics_students
print(only_one)  # {'Alice', 'Charlie', 'David', 'Eve'}

5.10.4 过滤数据

# 找出两个列表中的共同元素
list1 = [1, 2, 3, 4, 5]
list2 = [4, 5, 6, 7, 8]
common = set(list1) & set(list2)
print(common)  # {4, 5}

# 找出只在一个列表中出现的元素
unique_to_list1 = set(list1) - set(list2)
print(unique_to_list1)  # {1, 2, 3}

5.11 集合与列表、元组的比较

特性列表元组集合
可变性可变不可变可变(frozenset不可变)
顺序有序有序无序
重复元素允许允许不允许
语法方括号 []圆括号 ()花括号 {}(空集合用set())
索引支持支持不支持
用途存储有序序列存储不应改变的有序序列去重、成员测试、数学运算

5.12 集合的性能特点

集合基于哈希表实现,某些操作比列表高效:

import time
​
# 创建大量数据
large_list = list(range(1000000))
large_set = set(large_list)
​
# 测试成员检查性能
target = 999999# 列表成员测试
start_time = time.time()
result = target in large_list
list_time = time.time() - start_time
​
# 集合成员测试
start_time = time.time()
result = target in large_set
set_time = time.time() - start_time
​
print(f"列表成员测试时间: {list_time:.6f} 秒")
print(f"集合成员测试时间: {set_time:.6f} 秒")
print(f"集合比列表快 {list_time/set_time:.1f} 倍")

本章笔记:

  • 集合是一个无序且不重复的元素集。
  • 集合使用花括号创建,但空集合必须使用set()。
  • 集合会自动去除重复元素,元素没有固定顺序。
  • 集合支持添加、删除等操作,但元素必须是可哈希的(不可变类型)。
  • 集合支持丰富的数学运算:并集、交集、差集、对称差集等。
  • 集合关系运算可以检查子集、超集和不相交。
  • 冻结集合是不可变的集合。
  • 集合常用于去重、快速成员测试和数学集合运算。
  • 集合的成员测试效率远高于列表。