集合
集合(set)是一种无序、不重复的元素集合。它支持数学中的集合运算:并集、交集、差集、对称差集。集合中的元素必须是不可变(可哈希)的对象。
创建集合
# 用花括号(注意:空 {} 是字典,不是集合)
s = {1, 2, 3, 3, 3}
print s # set([1, 2, 3]),重复自动去重
# 用 set() 构造函数
s = set([1, 2, 3, 3])
print s # set([1, 2, 3])
# 空集合(必须用 set())
empty = set()
print type(empty) # <type 'set'>
not_set = {} # 这是空字典!
print type(not_set) # <type 'dict'>
添加和删除元素
s = {1, 2, 3}
# 添加单个元素
s.add(4)
print s # set([1, 2, 3, 4])
# 添加已存在的元素,无效果
s.add(3)
print s # set([1, 2, 3, 4])
# 删除元素
s.remove(3)
print s # set([1, 2, 4])
# remove 不存在的元素会报错
s.remove(10) # KeyError: 10
# discard:删除元素,不存在不报错
s.discard(10)
print s # 无变化
# pop():删除并返回任意元素
item = s.pop()
print item # 1(或其他元素,顺序不确定)
# clear():清空
s.clear()
print s # set([])
集合运算
a = {1, 2, 3, 4}
b = {3, 4, 5, 6}
# 并集:在 a 或 b 中的元素
print a | b # set([1, 2, 3, 4, 5, 6])
print a.union(b) # 同上
# 交集:同时在 a 和 b 中的元素
print a & b # set([3, 4])
print a.intersection(b) # 同上
# 差集:在 a 中但不在 b 中的元素
print a - b # set([1, 2])
print a.difference(b) # 同上
# 对称差集:只在 a 或只在 b 中的元素
print a ^ b # set([1, 2, 5, 6])
print a.symmetric_difference(b) # 同上
# 子集和超集
print a <= b # False,a 不是 b 的子集
print {3, 4} <= a # True
print a >= {1, 2} # True
实际应用
去重:
nums = [1, 2, 2, 3, 3, 3, 4]
unique = list(set(nums))
print unique # [1, 2, 3, 4](顺序可能不同)
注意:set 不保留顺序。如果需要去重且保留顺序,用普通循环或 collections.OrderedDict:
# 保留顺序的去重
seen = set()
result = []
for x in nums:
if x not in seen:
seen.add(x)
result.append(x)
print result # [1, 2, 3, 4]
成员检测:
# 列表查找是 O(n)
large_list = range(1000000)
print 999999 in large_list # 慢,需要遍历
# 集合查找是 O(1)
large_set = set(large_list)
print 999999 in large_set # 快,哈希查找
关系判断:
# 两个列表是否有共同元素
list1 = [1, 2, 3]
list2 = [3, 4, 5]
# 低效:O(n*m)
has_common = any(x in list2 for x in list1)
# 高效:O(n+m)
has_common = not set(list1).isdisjoint(list2)
集合推导式
与列表推导式类似:
# 平方集合(自动去重)
squares = {x**2 for x in range(10)}
print squares # set([0, 1, 4, 81, 64, 9, 16, 49, 25, 36])
# 过滤
odds = {x for x in range(20) if x % 2 == 1}
print odds # set([1, 3, 5, 7, 9, 11, 13, 15, 17, 19])
不可变集合 frozenset
frozenset 是不可变的集合,创建后不能添加或删除元素。因此它可以作为字典的键或另一个集合的元素:
# frozenset 作为字典键
locations = {
frozenset(["a", "b"]): "edge AB",
frozenset(["b", "c"]): "edge BC",
}
# 普通 set 不能作为键
# d = {set([1, 2]): "A"} # TypeError: unhashable type: 'set'
# frozenset 支持所有查询操作,不支持修改
fs = frozenset([1, 2, 3])
print 2 in fs # True
print fs | {3, 4} # frozenset([1, 2, 3, 4])
# fs.add(5) # AttributeError: 'frozenset' object has no attribute 'add'
集合 vs 列表 vs 字典
| 特性 | 列表 | 集合 | 字典 |
|---|---|---|---|
| 有序 | 是 | 否 | 否(Python 2) |
| 重复 | 允许 | 不允许 | 键不允许 |
| 查找 | O(n) | O(1) | O(1) |
| 用途 | 序列数据 | 去重、关系运算 | 键值映射 |