今天给大家介绍内置数据结构集合的用法。
看一下集合的思维导图:
add
,update
remove,discard,clear,pop
union,intersection,difference, symmetric_difference
issubset,issupperset,isdisjoint
在Python中怎么定义一个集合呢?
s = set() # 使用内置的set方法 >>> s = set() >>> s set() >>> type(s) <class 'set'> # 可以给集合赋初值 s = {1, 2, 3} # 使用大括号 # 但不能使用如下形式的定义集合 s = {} # 不能这么定义集合,使用type方法查看s的类型 >>> s = {} >>> type(s) <class 'dict'> s = {1, 2, 3} type(s) set
add方法,
s = {1, 2, 3} s s.add(4) s s.add(4) >>> s.add('a') >>> s {'a', 1, 2, 3, 4} # add一个列表 >>> s.add([4, 5, 6]) TypeError: unhashable type: 'list' # 为什么不能增加一个列表呢?由于集合使用hash来判断元素是否重复; # 由于列表是不能hash的,所以,集合的add方法不能增加一个列表到 # 已有的集合中 # add一个字符串 >>> s.add('abcde') >>> s {1, 2, 3, 4, 'a', 'abcde'} # add一个元组 >>> s.add((1, 2, 3)) >>> s {1, 2, 3, 4, (1, 2, 3), 'a', 'abcde'} # add一个类的实例 class A: pass a = A() hash(a)
当add一个已经存在的元素时,不会发生任何改变。
重要 为什么不能增加一个列表呢?由于集合使用hash来判断元素是否重复;由于列表是不能hash的,所以,集合的add方法不能增加一个列表到已有的集合中。内置数据类型中,可变的都是不可哈希的,而不可变的类型是可哈希的。list,set,bytearray,dict是不可hash的,所以不能作为set的元素;通常来说,内置类型,不可变类型是可hash的,可变类型是不可hash的。
update方法,
s = {1, 2, 3, 4} s.update([3, 4, 5, 6]) s # 已经把重复的元素去重了 set([1, 2, 3, 4]) # 使用set去重一个list list(set([1, 3, 2, 1, 2, 4]))
删除的方法,
# remove方法,但要移除的元素必须存在 s = {1, 2, 3, 4} s.remove(1) # 移除一个存在的 s.remove(10) # 移除一个不存在的 # discard方法,不要求要删除的元素是否存在于集合中 s.discard(2) # 移除一个存在的 s.discard(20) # 移除一个不存在的 # pop方法,会随机移除一个元素,但要求集合为非空 s = {3, 4, 5, 6} s.pop() s # clear方法,清除集合中的所有元素 s.clear()
删除集合元素总结:
集合的修改和查找,
没有一个方法可以直接的修改集合中的某个具体元素;因为没有一个方法,可以定位 其中的某个具体元素。
集合不能通过索引访问。集合没有访问单个元素的方法。集合不是线性结构,集合元素没有顺序。
集合也是可迭代的对象,
for x in set('lavenliu'): print(x)
集合可以用成员运算法,线性结构的成员运算,时间复杂度是O(n),集合的成员运算,时间复杂度是O(1)。
'l' in set('lavenliu')
集合的成员运算和其他线性结构的时间复杂度不同。做成员运算的时候,集合的效率远高于列表。集合的效率和集合的规模无关。
In[7]: lst = list(range(1000000)) In[8]: %%timeit ...: -1 in lst ...: 100 loops, best of 3: 13.7 ms per loop In[9]: lst = list(range(100000)) In[10]: %%timeit ...: -1 in lst ...: 1000 loops, best of 3: 1.39 ms per loop In[11]: s2 = set(range(1000000)) In[12]: %%timeit ...: -1 in s2 ...: 10000000 loops, best of 3: 57.5 ns per loop In[13]: s2 = set(range(100)) In[14]: %%timeit ...: -1 in s2 ...: 10000000 loops, best of 3: 58.4 ns per loop In[15]:
时间复杂度:
O(1) 常数复杂度 O(logn) 对数复杂度 O(n) 线性复杂度 O(n^2) 平方复杂度 O(n^3) 立方复杂度 O(2^n) 指数复杂度 O(n!) 阶乘复杂度
集合的运算:
存在集合A和B,对于集合C,如果C的每个元素既是A的元素,又是B的元素,并且A和B所有相同的元素都在C找到,那么C是A和B的交集。
集合A和B,当集合C的元素仅存在A中,但不存在B中,并且A中存在B中不存在的元素全部存在C中,那么C是A和B的差集。
如果把两个集合A和B看成是一个全集,对称差集是交集的补集。
实例演示,
a = {1, 2, 3} b = {2, 3, 4} # 并集 a.union(b) # 集合重载了按位或运算符,用于集合的并集运算 a | b # 并集的update版本 a.update(b) a # {1, 2, 3, 4} # 交集,不修改原来的集合,会返回新的集合 # 集合的交集运算,重载按位与运算符为交集运算。 # a.intersection(b) 等效于 a & b a.intersection(b) a & b # {2, 3} a.instersection_update(b) # instersection_update版本会原地修改,返回None # a = a.insertsection(b) # a = {2, 3} # b = {2, 3, 4} # 差集 # 差集没有交换律 a.difference(b) a - b # {1} # 差集也有update版本 a.difference_update(b) # 相当于a = a.difference(b) a # {1} # 集合的差集运算,重载减法运算符为交集运算。 # a.difference(b) 等效于 a - b a - b # {1} # 对称差集 # 对称差集具有交换律 a.symmetric_difference(b) # 集合的差集运算,重载异或运算符为对称差集运算。 a ^ b # {1, 4} # 得到的结果是a和b的非相同元素,(a | b) - (a & b) # 对称差集也有update版本 a.symmetric_difference_update(b) # 原地修改,返回None。相当于a = a.symmetric_difference(b) # 其他一些特性 a.union(b) == b.union(a) a.intersection(b) == b.intersection(a) a.difference(b) == b.difference(a) a.symmetric_difference == b.symmetric_difference(a)
集合相关的判断。超集与子集,isuperset,issubset
a = {1, 2, 3, 4} b = {3, 4} a.issuperset(b) b.issubset(a) a.issuperset(a) b.issubset(a)
isdisjoint方法判断两个集合是否不相交,如果有交集返回False,没有交集返回True。
a.isdisjoint(b) a.isdisjoint({5, 6})
一个例子:
def issubset(s1, s2): for x in s1: if x not in s2: return False return True def issuperset(s1, s2): for x in s2: if x not in s1: return False return True
举几个具体场景的例子,
# 用户输入了一批主机,这些主机肯定不能重复,可以这样来处理 # 这样,就不会在机器上执行重复的操作了 hosts = set(user_input.splitlines()) # 得到还在集合中的机器列表 in_progress_hosts = hosts - complete_hosts # 获得用户的所有输入的主机 hosts = input_a | input_b | input_c # 对多个目录下的文件去重
有一个API,它要有认证,并且有一定权限才可以访问,例如,要求满足权限A,B,C中任意一项,有一个用户具有权限B,C,D,那么此用户是否有权限访问此API。(判断是否集合是否相交,返回False说明相交,说明具有访问权限)
有一个任务列表,存储全部的任务,有一个列表,存储已经完成的任务,找出未完成的任务。
可变元素不能成为集合的元素。集合元素必须可hash。目前我们所知道的所有可变的数据类型是不可hash的,所有的不可变的数据类型都是可hash的。
本文分享自微信公众号 - 小白的技术客栈(XBDJSKZ),作者:lavenliu.cn
原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。
原始发表时间:2017-08-26
本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。
我来说两句