在上一篇《手把手陪您学Python》23——内置序列函数中,我们学习了4种Python中内置的序列函数,同时学习了利用序列函数构建字典的方法。
在这一篇中,我们将学习这一阶段中最后一种数据结构——集合。集合的概念我们并不陌生,在大学数学以及高中,都涉及到了一点集合的知识,像我们知道的交集、并集等,都是针对集合进行的操作。
今天,我们会对Python中集合的概念以及相关的操作方法给大家进行系统地讲解,同时还会将之前学习过的数据结构(列表、元组、字典)和标量(字符串、数字、布尔值)等加入到今天的示例中,以便大家能够对之前学过的内容有一个整体的认知和复习。
1、集合的定义
集合是一个无序的不重复元素序列,可以使用大括号{}或者set()函数创建集合。集合的元素可以是数字、布尔值、字符串、元组等不可变的类型,但不可以是列表、字典等可变的类型,也就是说集合的元素必须能够“哈希化”(可参见《手把手陪您学Python》22——字典中的扩展内容)。
同时,集合最重要的特性是“无序”和“不重复”,因此,集合无法被索引,重复的元素放入集合中会被“去重”。
In [1]: {1, 'a', True, (3, 2), 1} # 使用{}是最容易的定义集合方法,重复的元素会被去掉(True也是1,因此也会被去重),因为无序,顺序也可能会调整
Out[1]: {(3, 2), 1, 'a'}
In [2]: {[1, 2], 1} # 列表不能作为集合的元素
Out[2]: ---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-14-cb9a458f6989> in <module>
----> 1 {[1, 2], 1} # 列表不能作为集合的元素
TypeError: unhashable type: 'list'
In [3]: {{1:1}, 1} # 字典也不能作为集合的元素
Out[3]: ---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-15-97fed40bc698> in <module>
----> 1 {{1:1}, 1} # 字典也不能作为集合的元素
TypeError: unhashable type: 'dict'
使用set()函数定义集合时,set()会采用遍历的方式,对参数拆分后形成集合。对于不能被遍历的数据类型,不能够直接作为set()的参数,而需要将其作为元组的元素,元组作为set()的参数。
In [4]: set("Good") # 字符串被拆分为字母,同时去重
Out[4]: {'G', 'd', 'o'}
In [5]: set(123) # 数字因为不能被遍历,所以不能够使用set()生成集合
Out[5]: ---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-30-9becc342fd9e> in <module>
----> 1 set(123)
TypeError: 'int' object is not iterable
In [6]: set((123,)) # 注意定义只包含一个元素的元组的方法
Out[6]: {123}
因为set()的参数只能有一个,所以当定义包括多个元素的集合时,都要放入元组内。列表、字典因为能够被遍历,所以也能够作为set()的参数,并将其元素添加到集合中。
In [7]: set(("Good", 123, 123))
Out[7]: {123, 'Good'}
In [8]: set(["Good", 123, 123])
Out[8]: {123, 'Good'}
In [9]: set({1:2,'3':'4'}) # 需要注意的是,当字典作为元素时,只有键会被遍历并添加到集合中
Out[9]: {1, '3'}
在定义空集合时,只能使用set()函数,因为{}是定义空字典的方法。
In [10]: print("set()的类型是{},{{}}的类型是{}".format(type(set()), type({}))) # 注意字符串的格式化输出方法中,输出{}的方法
Out[10]: set()的类型是<class 'set'>,{}的类型是<class 'dict'>
2、集合元素的增加
在集合中增加元素的方法有两种,一种是.add()方法,一种是.update()方法。
.add()方法只能有一个参数,且参数必须是不可变的(即可以哈希化)。
In [11]: set1 = set((1, 2, 3))
set1.add(4)
set1
Out[11]: {1, 2, 3, 4}
In [12]: set1.add(4, 5, 6) # 只能有一个参数
set1
Out[12]: ---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-6-fc53492f5320> in <module>
----> 1 set1.add(4, 5, 6)
2 set1
TypeError: add() takes exactly one argument (3 given)
In [13]: set1.add((4, 5, 6)) # 元组中包含的多个元素,只作为一个元素(元组)添加到集合中,这是与set()函数的区别
set1
Out[13]: {(4, 5, 6), 1, 2, 3, 4}
In [14]: set1.add([4, 5, 6]) # 列表、字典因为都是可变的,不能作为.add()的参数
set1
Out[14]: ---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-9-ed1640e4e4fc> in <module>
----> 1 set1.add([4, 5, 6]) # 列表、字典因为都是可变的,不能作为.add()的参数
2 set1
TypeError: unhashable type: 'list'
.update()方法添加元素的方式与.add()完全不同,后者是参数是什么元素,就在集合中添加什么元素,而前者是通过遍历的方式,将参数中的所有元素进行遍历,一一添加到集合中。
因此,像数字、布尔值这种不能被遍历的数据类型,是不能作为.update()方法的参数的。而列表、字典等可变的元素,虽然不能作为集合的元素,但是可以通过.update()方法进行遍历,而将其元素添加到集合中,而且.update()方法也不限制元素的个数。
In [15]: set2 = set((1, 2, 3))
In [16]: set2.update(4) # 数字不能遍历,所以报错
set2
Out[16]: ---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-16-5573d88f6ffa> in <module>
----> 1 set2.update(4) # 数字不能遍历,所以报错
2 set2
TypeError: 'int' object is not iterable
In [17]: set2.update((4)) # (4)代表4加上小括号的数学运算,所以还是4,报错
set2
Out[17]: ---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-17-1e5a31168b76> in <module>
----> 1 set2.update((4)) # (4)代表4加上小括号的数学运算,所以还是4,报错
2 set2
TypeError: 'int' object is not iterable
In [18]: set2.update((4,)) # 注意只有一个元素的元组的定义方法
set2
Out[18]: {1, 2, 3, 4}
In [19]: set2.update((4, 5), "Good", ['a', 'd', True, False], {6:7, '8':'9', 'X':'Y'}) # 请大家试试看能否得到与输出结果一致的答案,注意字典的遍历结果是什么
set2
Out[19]: {1, 2, 3, 4, 5, 6, '8', False, 'G', 'X', 'a', 'd', 'o'}
3、集合元素的删除
集合元素的删除方法一共有三种,分别是.remove()方法、.discard()方法和.pop()方法,此外还有一个清空集合的方法.clear()。
.remove()方法可以直接从集合中删除特定元素,如果该元素不存在,则报错。
In [20]: set3 = {1, 2, 3, 'a', 'b', 'c'}
In [21]: set3.remove(3)
set3
Out[21]: {1, 2, 'a', 'b', 'c'}
In [22]: set3.remove(3) # 3已经在上一步中被删除了,因此报错
set3
Out[22]: ---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
<ipython-input-27-6cccfd8ba26e> in <module>
----> 1 set3.remove(3) # 3已经在上一步中被删除了,因此报错
2 set3
KeyError: 3
.discard()方法也可以直接从集合中删除特定元素,但该元素不存在时,不会报错。
In [23]: set3.remove('b')
set3
Out[23]: {1, 2, 'a', 'c'}
In [24]: set3.discard('b') # 虽然'b'已经在上一步中被删除的,也不会报错
set3
Out[24]: {1, 2, 'a', 'c'}
.pop()方法则是随机从集合中删除某元素,并且返回被删除元素的元素值。虽然说是随机删除,但是在交互模式中,.pop()方法会删除集合排序后左侧的第一个元素(虽然无序,但是集合一般会按ASCII的顺序进行排序,从前面的实例中也可以看到)。
In [25]: set3.pop() # 排序后左侧第一个元素是1
Out[25]: 1
In [26]: set3
Out[26]: {2, 'a', 'c'}
.clear()方法就是将集合中的元素全部删除,形成一个空集合。
In [27]: set3.clear()
set3
Out[27]: set()
4、集合的运算
集合的运算就是指我们比较熟悉的交集、并集等,此外,还有我们不太熟悉的差集和对称差集。
In [28]: set4 = {1, 2, 3, 4, 5}
set5 = {4, 5, 6, 7, 8, 9}
In [29]: set4.union(set5) # 并集,或者使用二元操作符(set4 | set5)
Out[29]: {1, 2, 3, 4, 5, 6, 7, 8, 9}
In [30]: set4 | set5 # 其它运算不再列举二元操作符的实例
Out[30]: {1, 2, 3, 4, 5, 6, 7, 8, 9}
In [31]: set4.intersection(set5) # 交集,或者使用二元操作符(set4 & set5)
Out[31]: {4, 5}
In [32]: set4.difference(set5) # 差集,即在set4但不在set5的元素,或者使用二元操作符(set4 - set5)
Out[32]: {1, 2, 3}
In [33]: set4.symmetric_difference(set5) # 对称差集,即在set4和set5但不同时在set4和set5的元素,或者使用二元操作符(set4 ^ set5)
Out[33]: {1, 2, 3, 6, 7, 8, 9}
在应用上述方法进行运算时,并不会改变set4和set5的值。如果想在运算的同时,改变se4的值,就需要用到.update()方法,或者在上述方法的基础上增加update字样。同时二元操作符也有相应的改变,就像我们之前介绍的a=a+1与a+=1等效一样。
In [34]: set4.update(set5) # 并集并赋值给set4,或者使用二元操作符(set4 |= set5)
set4
Out[34]: {1, 2, 3, 4, 5, 6, 7, 8, 9}
In [35]: set4 = {1, 2, 3, 4, 5}
set5 = {4, 5, 6, 7, 8, 9}
set4.intersection_update(set5)
set4 # 交集并赋值给set4,或者使用二元操作符(set4 &= set5)
Out[35]: {4, 5}
其它类似的方法还有a.difference_update(b)(二元操作符:a -= b),a. symmetric_difference_update(b)(二元操作符:a ^= b),这里就不一一举例了。
5、集合的判断
集合的判断主要是判断一个集合是否包含与另一集合中的相关运算。
In [36]: set6 = {1, 2, 3, 4, 5}
set7 = {1, 2, 3}
In [37]: set7.issubset(set6) # set7是不是set6的子集
Out[37]: True
In [38]: set6.issuperset(set7) # set6是不是set7的父集
Out[38]: True
In [39]: set8 = {6, 7}
set6.isdisjoint(set8) # 如果set6和set8没有交集,返回True
Out[39]: True
In [40]: set9 = {1, 2, 3}
1 in set9 # 可以使用我们之前学过的in,来判断一个元素是否包含在集合中
Out[40]: True
In [41]: set10 = {1, 2, 3}
set9 == set10 # 判断两个集合是否相同,这里不能用is,因为内存地址不同
Out[41]: True
6、集合的函数
上面我们介绍的都是集合的方法,下面我们介绍一个集合的函数len(),也就是计算集合的元素个数的函数。
In [42]: len({1, 'a', True, (3, 2), 1})
Out[42]: 3
以上就是我们对于Python集合的介绍了,至此我们已经将Python中最基础的几个数据结构都介绍完了。下一篇,我们将介绍列表、集合和字典的推导式,这也是Python最受欢迎的语言特性之一,敬请关注。
感谢阅读本文!如有任何问题,欢迎留言,一起交流讨论^_^
要阅读《手把手陪您学Python》系列文章的其他篇目,请关注公众号点击菜单选择,或点击下方链接直达。
《手把手陪您学Python》3——PyCharm的安装和配置
《手把手陪您学Python》5——Jupyter Notebook
For Fans:关注“亦说Python”公众号,回复“手24”,即可免费下载本篇文章所用示例语句。
