讲解

集合(set)是无序、不重复的元素容器,用花括号或 set() 创建:s = {1, 2, 3}。注意空集合只能写 set(),{} 是空字典。集合的元素必须可哈希(和字典键同规则)。它的两个核心能力是:自动去重——list(set(data)) 是列表去重的经典一行;以及 O(1) 的成员判断——x in 十万级集合依然瞬间完成,而列表的 in 要逐个比对。需要频繁「在不在」判断时,先把数据装进集合。

集合支持数学里的集合运算:并集 a | b、交集 a & b、差集 a - b(在 a 不在 b)、对称差集 a ^ b(恰在其中一个里)。对应的方法版本是 union、intersection、difference、symmetric_difference,方法版接受任意可迭代对象而运算符两边必须都是集合。子集判断用 <= 或 issubset,a.issuperset(b)、a.isdisjoint(b)(无交集)也常用。

修改集合用 add 加元素、discard 删除(不存在也不报错)、remove 删除(不存在抛 KeyError)、pop 随机弹出一个(因为无序,别依赖弹出的具体值)、clear 清空。如果需要「不可变的集合」(比如想当字典键),用 frozenset。最后强调「无序」:遍历集合的顺序不保证,既非插入序也非排序序,且受哈希随机化影响每次运行可能不同——要顺序请先 sorted()。

示例

# 创建与去重
nums = [1, 2, 2, 3, 3, 3]
unique = set(nums)
print('去重:', sorted(unique))
print('回列表:', list(set(nums)))

# 空集合必须用 set()
empty = set()
print(type(empty), type({}))

# 成员判断:集合的主场
valid_codes = {'A101', 'B202', 'C303'}
for code in ['A101', 'X999']:
    print(code, '有效吗:', code in valid_codes)

# 集合运算
python_students = {'小明', '小红', '小刚'}
java_students = {'小红', '小丽'}
print('都学了(交集):', python_students & java_students)
print('学了一门(并集):', python_students | java_students)
print('只学 Python(差集):', python_students - java_students)
print('只学一门(对称差集):', python_students ^ java_students)

# 子集判断
print('子集:', {'小明'} <= python_students)

# 增删
tags = {'python', 'tutorial'}
tags.add('beginner')
tags.discard('不存在的')  # 不报错
print('标签:', sorted(tags))

# frozenset 可以当字典键
routes = {frozenset({'北京', '上海'}): '高铁 4.5 小时'}
print('查路线:', routes[frozenset({'上海', '北京'})])

常见坑

  • 用 {} 创建空集合:那是空字典!空集合只能 set(),这处不一致是历史遗留。
  • 依赖集合的遍历顺序:集合无序,遍历顺序既不保证也不稳定。要展示顺序先 sorted(s)。
  • 把可变对象放进集合:s.add([1, 2]) 抛 TypeError,和字典键同理。需要「集合的集合」用 frozenset。
  • 大列表里循环做 in 判断:if x in big_list 每查一次扫一遍,放在循环里就是 O(n²)。先 big_set = set(big_list),查询降到 O(1)。

小结

集合自动去重、成员判断 O(1);交并差用 & | - ^;空集合写 set();无序,要顺序先 sorted。下一节进入代码复用的核心:函数。