1.创建集合
创建集合有三个方法:
- 使用花括号,元素之间以逗号分隔:{“FishC”, “Python”}
- 使用集合推导式:{s for s in “FishC”}
- 使用类型构造器,也就是 set():set(“FishC”)
2.集合的随机性
>>> set("FishC")
{'i', 'C', 's', 'F', 'h'}
从这里我们不难发现,集合无序的特征,传进去的是 ‘F’、‘i’、‘s’、‘h’、‘C’,它这里显示的却是 ‘i’、‘C’、‘s’、‘F’、‘h’,在你们的电脑上结果还可能不一样,这就是随机性。
由于集合是无序的,所以我们不能使用下标索引的方式去访问它:
>>> s = set("FishC")
>>> s[0]
Traceback (most recent call last):
File "<pyshell#1>", line 1, in <module>
s[0]
TypeError: 'set' object is not subscriptable
不过我们可以使用 in 和 not in 来判断某个元素是否存在于集合中:
>>> 'C' in s
True
>>> 'c' not in s
True
3.访问集合
如果想要访问集合中的元素,可以使用迭代的方式:
>>> for each in s:
... print(each)
...
F
h
i
s
C
4. 集合必杀技 —— 去重
集合另外一个特点就是唯一性,小甲鱼本鱼觉得,这也是集合最大的优势。比如利用集合,咱们就可以轻松地实现去重的操作:
>>> set([1, 1, 2, 3, 5])
{1, 2, 3, 5}
在实际开发中,我们经常需要去检测一个列表中是否存在相同的元素?
那么在没有学习过集合之前,我们很有可能需要通过迭代来统计每个元素出现的次数,从而判断是否唯一……
但是,现在,咱们只需要这么写:
>>> s = [1, 1, 2, 3, 5]
>>> len(s) == len(set(s))
False
>>> s = [1, 2, 3, 5]
>>> len(s) == len(set(s))
True
5. 集合的方法
(1)列表、元组、字符串、字典它们都有一个 copy() 方法,那么集合也不例外:
>>> t = s.copy()
>>> t
{'h', 's', 'i', 'F', 'C'}
如果我们要检测两个集合之间是否毫不相干,可以使用 isdisjoint(other) 方法:
>>> s.isdisjoint(set("Python"))
False
>>> s.isdisjoint(set("JAVA"))
True
那么这个参数它并不要求必须是集合类型,可以是任何一种可迭代对象:
>>> s.isdisjoint("Python")
False
>>> s.isdisjoint("JAVA")
True
下面也是一样的,传入的参数,都只要求是可迭代对象的类型即可。
如果我们要检测该集合是否为另一个集合的子集,可以使用 issubset(other) 方法:
>>> s.issubset("FishC.com.cn")
True
如果我们要检测该集合是否为另一个集合的超集,可以使用 issuperset(other) 方法(对于两个集合 A、B,如果集合 B 中任意一个元素都是集合 A 中的元素,我们就说这两个集合有包含关系,称集合 A 为集合 B 的超集):
>>> s.issuperset("Fish")
True
除了检测子集和超集,我们还可以计算当前集合和其它对象共同构造的并集、交集、差集以及对称差集。
并集,就是将集合与其它集合的元素合并在一起,组成一个新的集合:
>>> s.union({1, 2, 3})
{1, 2, 3, 'h', 's', 'i', 'F', 'C'}
交集,就是找到多个集合之间共同的那些元素
>>> s.intersection("Fish")
{'h', 's', 'i', 'F'}
差集,就是找出存在于该集合,但不存在于其它集合中的元素:
>>> s.difference("Fish")
{'C'}
同时,上面的这三个都是支持多个参数的:
>>> s.union({1, 2, 3}, "Python")
{1, 2, 3, 'y', 'h', 'n', 'i', 'P', 's', 'o', 't', 'C', 'F'}
>>> s.intersection("Php", "Python")
{'h'}
>>> s.difference("Php", "Python")
{'s', 'C', 'F', 'i'}
最后一个是求对称差集,就是排除掉 s 集合和 other 容器中共有的元素后,剩余的所有元素,这个只能支持一个参数:
>>> s.symmetric_difference("Python")
{'t', 'y', 'F', 's', 'P', 'C', 'n', 'o', 'i'}
好了,那么上面这 6 种常见的操作,Python 也提供了相应的运算符,可以直接进行运算。
检测子集可以使用小于等于号(<=):
>>> s <= set("FishC")
True
那么检测真子集我们可以使用小于号(<):
>>> s < set("FishC")
False
>>> s < set("FishC.com.cn")
True
那么反过来,使用大于号(>)和大于等于号(>=)就是检测真超集和超集:
>>> s > set("FishC")
False
>>> s >= set("FishC")
True
并集使用管道符(|):
>>> s | {1, 2, 3} | set("Python")
{1, 2, 3, 'y', 'h', 'n', 'i', 'P', 's', 'o', 't', 'C', 'F'}
交集使用 and 符号(&):
>>> s & set("Php") & set("Python")
{'h'}
差集使用减号(-):
>>> s - set("Php") - set("Python")
{'s', 'C', 'F', 'i'}
对称差集使用脱字符(^):
>>> s ^ set("Python")
{'t', 'y', 'F', 's', 'P', 'C', 'n', 'o', 'i'}
注意:使用运算符的话,符号两边都必须是集合类型的数据才可以,不然会报错。
>>> s <= "FishC"
Traceback (most recent call last):
File "<pyshell#46>", line 1, in <module>
s <= "FishC"
TypeError: '<=' not supported between instances of 'set' and 'str'
>>> s | [1, 2, 3]
Traceback (most recent call last):
File "<pyshell#15>", line 1, in <module>
s | [1, 2, 3]
TypeError: unsupported operand type(s) for |: 'set' and 'list'
6.冻结的集合
Python 将集合细分为可变和不可变两种对象,前者是 set(),后者是 frozenset():
>>> t = frozenset("FishC")
>>> t
frozenset({'s', 'C', 'i', 'F', 'h'})
被冻结的集合(frozenset())是不支持修改的。
如果我们尝试修改它,那么可怕的事情就会发生:
>>> t.update([1, 1], "23")
Traceback (most recent call last):
File "<pyshell#6>", line 1, in <module>
t.update([1, 1], "23")
AttributeError: 'frozenset' object has no attribute 'update'
7.仅使用与set()对象的方法
update(*others) 方法使用 others 容器中的元素来更新集合:
>>> s = set("FishC")
>>> s
{'s', 'C', 'i', 'F', 'h'}
>>> s.update([1, 1], "23")
>>> s
{'s', 1, 'C', 'i', 'F', 'h', '3', '2'}
intersection_update(*others)、difference_update(*others) 和 symmetric_difference_update(other) 分别是使用前面讲过的交集、差集和对称差集的方式来更新集合:
>>> s.intersection_update("FishC")
>>> s
{'s', 'C', 'i', 'F', 'h'}
>>> s.difference_update("Php", "Python")
>>> s
{'s', 'C', 'i', 'F'}
>>> s.symmetric_difference_update("Python")
>>> s
{'s', 't', 'C', 'o', 'h', 'i', 'y', 'F', 'n', 'P'}
如果希望要单纯地往集合里添加数据,可以使用 add(elem) 方法:
>>> s.add("45")
>>> s
{'s', 't', 'C', 'o', 'h', 'i', 'y', 'F', '45', 'n', 'P'}
在集合中删除某个元素,可以使用 remove(elem) 或者 discard(elem) 方法:
>>> s.remove("瓦迈")
Traceback (most recent call last):
File "<pyshell#15>", line 1, in <module>
s.remove("瓦迈")
KeyError: '瓦迈'
>>> s.discard("瓦迈")
删除还有一个 pop() 方法,用于随机从集合中弹出一个元素:
>>> s.pop()
's'
>>> s.pop()
't'
>>> s.pop()
'C'
>>> s
{'o', 'h', 'i', 'y', 'F', '45', 'n', 'P'}
最后,clear() 方法就是将集合清空:
>>> s.clear()
>>> s
set()
8.可哈希
想要正确地创建字典和集合,是有一个刚性需求的 —— 那就是字典的键,还有集合的元素,它们都必须是可哈希的。
如果一个对象是可哈希的,那么就要求它的哈希值必须在其整个程序的生命周期中都保持不变。
通过 hash() 函数,可以轻松获取一个对象的哈希值:
>>> hash(1)
1
>>> hash(1.0)
1
>>> hash(1.001)
2305843009213441
Python 中大多数不可变对象是可哈希的,而那些可变的容器则不哈希:
>>> hash("FishC")
2090433017907150752
>>> hash([1, 2, 3])
Traceback (most recent call last):
File "<pyshell#36>", line 1, in <module>
hash([1, 2, 3])
TypeError: unhashable type: 'list'
前面我们说了,只有可哈希的对象,才有资格作为字典的键,以及集合的元素:
>>> {"Python":520, "FishC":1314}
{'Python': 520, 'FishC': 1314}
>>> {"Python", "FishC", 520, 1314}
{520, 1314, 'Python', 'FishC'}
9.集合的嵌套
如果要实现一个嵌套的集合,可不可行?
>>> x = {1, 2, 3}
>>> y = {x, 4, 5}
Traceback (most recent call last):
File "<pyshell#39>", line 1, in <module>
y = {x, 4, 5}
TypeError: unhashable type: 'set'
这样写是不行的,因为集合它是一个可变的容器,而可变的容器则是不可哈希。
那我们非要将集合嵌套,还有没有办法?
有!
没错,使用 “冰山美人” frozenset() 对象:
>>> x = frozenset(x)
>>> y = {x, 4, 5}
>>> y
{frozenset({1, 2, 3}), 4, 5}