Python内置数据结构之集合set

1 集合的基本概念

在计算机科学中,集合(collection)是一组可变数量的数据项(也可能是0个)的组合,这些数据项可能共享某些特征,需要以某种操作方式一起进行操作。一般来讲,这些数据项的类型是相同的,或基类相同(若使用的语言支持继承)。列表(或数组)通常不被认为是集合,因为其大小固定,但事实上它常常在实现中作为某些形式的集合使用。

集合(collection)的种类包括列表,集,多重集,树和图。枚举类型可以是列表或集。

2 集合(集)set

2.1 set的基本概念

与列表不同,在集(set)中,数据项是无序的,也不允许存在相同数据项。集(set)支持添加、删除和查找项目。一些语言内建对集(set)的支持,而在其它语言中,可以利用散列表实现集。Python中内建支持set类型

set是 可变的无序的不重复 的元素的集合

2.2 set的定义、初始化

  • set() -> new empty set object
  • set(iterable) -> new set object
In [1]: s1 = set()

In [2]: s1
Out[2]: set()

In [3]: s2 = set(range(5))

In [4]: s2
Out[4]: {0, 1, 2, 3, 4}

In [5]: s3 = set(list(range(10)))

In [6]: s3
Out[6]: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}

In [7]: s4 = {}    #这实际上定义了一个新字典

#In [14]: type(s4)
#Out[14]: dict

In [8]: s4 
Out[8]: {}       #这是一个空字典

In [9]: s5 = {9,10,11}

In [10]: s5
Out[10]: {9, 10, 11}

In [11]: s6 = {(1,2),3,'a'}

In [12]: s6
Out[12]: {(1, 2), 3, 'a'}

In [13]: s7 = {[1],(1,),1}
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-13-aa063e638452> in <module>
----> 1 s7 = {[1],(1,),1}

TypeError: unhashable type: 'list'

由以上可知,在定义、初始化一个set的时候,有几点要注意。

  1. set的元素要求必须可以hash,不可hash的元素加入set会报错TypeError
  2. set是无序的,元素不可以使用索引
  3. set可以迭代
  4. {}代表一个空字典,set不能像元组、列表、字符串一样只需要在符号(如中括号,小括号,引号)中留空来定义一个空容器

2.3 set元素的增加

  • add(element)
  • 增加一个元素到set中
  • 如果元素存在,则什么都不做
In [17]: s1 = {1,2,3,4,5,6,7,8,9}

In [18]: s1.add(9)

In [19]: s1
Out[19]: {1, 2, 3, 4, 5, 6, 7, 8, 9}

In [20]: s1.add(99)

In [21]: s1
Out[21]: {1, 2, 3, 4, 5, 6, 7, 8, 9, 99}  
  • update(*others)
  • 合并其他元素到set中来
  • 参数others必须是可迭代对象
  • 就地修改
In [27]: s1 = {1,2,3,4,5}

In [28]: s1.update(range(8))

In [29]: s1
Out[29]: {0, 1, 2, 3, 4, 5, 6, 7}
#由于set中的元素是不可复制的,这个操作实际上只增加了6,7两个元素
In [30]: s1.update(range(9),range(11,20))

In [31]: s1
Out[31]: {0, 1, 2, 3, 4, 5, 6, 7, 8, 11, 12, 13, 14, 15, 16, 17, 18, 19}
#update方法可以添加多个可迭代对象,一次把元素添加到set中去

2.4 set删除

  • remove(element)
  • 从set中移除一个元素
  • 元素不存在,抛出KeyError异常。
In [1]: s1 = {1,2,3,4,5}

In [2]: s1.remove(5)

In [3]: s1
Out[3]: {1, 2, 3, 4}
#element存在,成功移除

In [4]: s1.remove(100)
#element不存在,报错KeyError
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-4-685aafef4353> in <module>
----> 1 s1.remove(100)

KeyError: 100
  • discard(element)
  • 从set中移除一个元素
  • 元素不存在,什么都不做
In [7]: s1 = {1,2,3,4,5}

In [8]: s1.discard(1)

In [9]: s1
Out[9]: {2, 3, 4, 5}
#元素存在,移除成功
In [10]: s1.discard(100)

In [11]: s1
Out[11]: {2, 3, 4, 5}
#元素不存在,移除失败。无报错或其他任何操作
  • pop() -> item
  • 移除并返回任意元素
  • 空集返回KeyError

因为set是无序的,无法指定索引,只能随机移除

In [12]: s1 = {1,2,3,4,5}

In [13]: s1.pop()
Out[13]: 1
#随机移除,返回移除值1
In [14]: s1 = set()

In [15]: s1.pop()
#s1为空集,无法移除,报错KeyError
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-15-095118de218b> in <module>
----> 1 s1.pop()

KeyError: 'pop from an empty set'
  • clear()
  • 移除所有元素
In [16]: s1 = {1,2,3,4,5}

In [17]: s1.clear()

In [18]: s1
Out[18]: set()

2.5 set的修改、查询

  • 修改
  • 要么删除,要么加入新的元素

set是无序的,无法通过索引指定某一个元素进行修改。所以只有先删除后增加的操作。事实上,修改这个词也只有在有序容器中才有意义,set内部元素本身无序,不存在修改的。

  • 查询
  • 非线性结构,无法查询
  • 遍历
  • 可以迭代所有元素
In [24]: s1 = {1,2,3,4,5}

In [25]: for i in s1:
    ...:     print(i)
    ...:
1
2
3
4
5

虽然set是无序的,但是仍然可以迭代。有序无序和可否迭代无关。

  • 成员运算符
  • in和not in可以判断元素是否在set中
In [26]: s1 = {1,2,3,4,5}

In [27]: 5 in s1
Out[27]: True

In [28]: 55 in s1
Out[28]: False

set中做成员运算符的操作和list相比,不用遍历,效率比较高

2.6 set和线性结构

  • 线性结构的查询时间复杂度是O(n),即随着数据规模的增大而耗时

  • set、dict等结构,内部使用hash值作为key,时间复杂度可以做到O(1),查询时间和数据规模无关

  • 可hash
  • 数值型int,float,complex

  • 布尔型True,False

  • 字符串string,bytes

  • 元组tuple

  • None

  • 以上都是不可变类型,是可哈希类型,hashable

  • set的元素必须是可hash的。(所以set不能成为set的元素)

3 集合运算

3.1 集合运算和集合的一些基本概念

  • 全集
  • 所有元素的集合。例如实数集,所有师叔组成的集合就是全集。
  • 子集subset和超级superset
  • 一个集合A所有元素都在另一个集合B内,A就是B的子集,B是A的超集
  • 真子集和真超集
  • A是B的子集,且A不等于B,则A是B的真子集,B是A的真超集
  • 并集:多个集合合并的结果

  • 交集:多个集合的公共部分

  • 差集:集合中除去和其他集合的公共部分

3.2 集合运算

3.2.1并集

  • 将两个集合A和B的所有的元素合并在一起,组成的集合称为集合A和集合B的并集
如韦恩图所示
  • union(*others)

  • 返回和多个集合合并后的新的集合

In [29]: s1 = {1,2,3}

In [30]: s2 = {6,7,9}

In [31]: s1.union(s2)
Out[31]: {1, 2, 3, 6, 7, 9}

In [32]: s3 = {1,2,3}

In [33]: s1.union(s3)
Out[33]: {1, 2, 3}
  • | 运算符重载
  • 等同于union
In [34]: s1 = {1,2}

In [35]: s2 = {5,6}

In [36]: s1 |s2
Out[36]: {1, 2, 5, 6}
  • update(*others)
  • 和多个集合合并,就地修改
In [38]: s1 = {1,2}

In [39]: s2 = {'a','b'}

In [40]: s3 = {b'332'}

In [41]: s1.update(s2,s3)

In [42]: s1
Out[42]: {1, 2, 'a', 'b', b'332'}
  • |=
  • 等同于update

3.2.2 交集

  • 集合A和B,由所有属于A且属于B的元素组成的集合
    image
  • intersection(*others)

  • 返回和多个集合的交集
In [1]: s1 = set(range(10))

In [2]: s2 = {'a',3,4,7}

In [3]: s3 = {0}

In [4]: s1.intersection(s2,s3)
Out[4]: set()
# s1,s2,s3无共同交集,返回空集
In [1]: s1 = set(range(10))

In [2]: s2 = {'a',0,9,'sss'}

In [3]: s3 = {0,1,2,3,4,5,6,7}

In [4]: s1.intersection(s2,s3)
Out[4]: {0}
# s1,s2,s3有共同元素0,返回由0组成的集合
  • &
  • 等同于intersection
In [7]: s1 = set(range(10))

In [8]: s2 = set(range(5))

In [9]: s1 & s2
Out[9]: {0, 1, 2, 3, 4}
# s2 是s1的子集,返回了由s2中全部元素组成的集合
  • intersection_update(*others)
  • 获取和多个集合的交集,并就地修改
In [10]: s1 = {'a',1,2,3,4,5,6,7}

In [11]: s2 = set(range(1,5))

In [12]: s3 = {4,5,6,7,8,9,0}

In [13]: s1.intersection_update(s2,s3)

In [14]: s1
Out[14]: {4}
# s1已经被修改为之前的s1,s2,s3的交集
  • &=
  • 等同intersection_update

3.2.3 差集

  • 集合A和B,由所有属于A且不属于B的元素组成的集合


    image
  • difference(*others)
  • 返回和多个集合的差集
In [15]: s1 = set(range(15))

In [16]: s2 = set(range(7,10))

In [17]: s3 = {1,4,7,9,5}

In [18]: s1.difference(s2,s3)
Out[18]: {0, 2, 3, 6, 10, 11, 12, 13, 14}
# 返回了s1和s2、s3的差集
  • 等同diffrence
  • difference_update(*others)
  • 获取和多喝集合的差集并就地修改
In [19]: s1 = set(range(15))

In [20]: s2 = set(range(7,10))

In [21]: s3 = {1,4,7,9,5}

In [22]: s1.difference_update(s2,s3)

In [23]: s1
Out[23]: {0, 2, 3, 6, 10, 11, 12, 13, 14}
#s1修改为s1和s2、s3的差集

In [28]: s1 = set(range(15))

In [29]: s2 = set(range(10))

In [30]: s3 = set(range(10,15))

In [31]: s1.difference_update(s2,s3)

In [32]: s1
Out[32]: set()
#当s1和s2、s3差集为空时,s1被修改为空集
  • -=
  • 等同于diffrence_update()

3.2.4 对称差集

  • 集合A和B,由所有不属于A和B的交集元素组成的集合,记作(A - B)∪(B - A)


    image
  • sysmmetric_differece(other)

  • 返回和另一个集合的对称差集
  • ^
  • 等同sysmmetric_differece()
In [33]: s1 = set(range(10))

In [34]: s2 = set(range(7,15))

In [35]: s1 ^ s2
Out[35]: {0, 1, 2, 3, 4, 5, 6, 10, 11, 12, 13, 14}
#返回的是A对B的差集和B对A的差集的并集
#如果A等于B返回空集
  • sysmmetric_differece_update(other)
  • 获取和另一个集合的对称差集并就地修改
  • ^=
  • 等同于sysmmetric_differece_update()
In [33]: s1 = set(range(10))

In [34]: s2 = set(range(7,15))

In [36]: s1 ^= s2

In [37]: s1
Out[37]: {0, 1, 2, 3, 4, 5, 6, 10, 11, 12, 13, 14}
#s1被修改为s1和s2的对称差集

3.3 集合运算的其他操作

  • issubset(other)、 <=
  • 判断当前集合是否是另外一个集合的子集
In [38]: s1 = set(range(7))

In [39]: s2 = {1,3,5}

In [40]: s2 <= s1
Out[40]: True
  • set1 < set2
  • 判断set1是否是set2的真子集

由于这些判断太简单了,就不贴代码了

  • issuperset(other)、 >=

  • 判断当前集合是否是other的超集

  • set1 > set2

  • 判断set1是否是set2的真超集

  • isdisjoint(other)

  • 当前集合和另外一个集合是否由交集,没有交集,返回True

In [41]: s1 = set(range(10))

In [42]: s2 = {1,3,7}

In [43]: s1.isdisjoint(s2)
Out[43]: False

In [44]: s3 = {-1,-3}

In [45]: s1.isdisjoint(s3)
Out[45]: True
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,651评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,468评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,931评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,218评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,234评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,198评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,084评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,926评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,341评论 1 311
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,563评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,731评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,430评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,036评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,676评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,829评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,743评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,629评论 2 354

推荐阅读更多精彩内容