Python集合详解

# ------------------------------------集合论------------------------------------
"""
"集"这个概念在Python中算是比较年轻的,同时它的使用率也比较低.set和它的不可变是姊妹类型frozenset直到Python2.3才首次以模块的形式出现,
然后在Python2.6中它们升级成为内置类型.
"""
# 集合的本质是许多唯一对象的聚集.因此,集合可以用于去重.
l1 = ['spam', 'spam', 'eggs', 'spam']
s1 = set(l1)
print(s1)  # {'spam', 'eggs'}
print(list(s1))  # ['spam', 'eggs']


# 利用这些运算符可以省去不必要的循环和逻辑操作
s1 = {1, 2, 3, 4}
s2 = {3, 4, 5, 6}
print(s1 | s2)  # {1, 2, 3, 4, 5, 6}  合集
print(s1 & s2)  # {3, 4}  交集
print(s1 - s2)  # {1, 2}  差集

# needles的元素在haystack里出现的次数,两个变量都是set类型
needles = {1, 2, 3, 4}
haystack = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
found = len(needles & haystack)  # 交集  这比下面的形式速度要快一点
print(found)

found = 0
for n in needles:
    if n in haystack:
        found += 1

# 就算手头没有集合,我们也可以随时建立集合
found = len(set(needles) & set(haystack))
found2 = len(set(needles).intersection(haystack))
"""
除了速度极快的查找功能(这也得归功于它背后的散列表),内置的set和frozenset提供了丰富的功能和操作,不但让创建集合的方式丰富多彩,
而且对于set来讲,我们还可以对集合里已有的元素进行修改.
"""

# ------------------------------------集合字面量------------------------------------
"""
除空集之外,集合的字面量---{1} {1, 2},等等---看起来跟它的数学形式一样.如果是空集,那么必须写成set()的形式.
不要忘了,如果要创建一个空集,你必须用不带任何参数的构造方法set().
如果只是写成{}的形式,那你创建的其实是个空字典.

像{1, 2, 3}这种字面量语法相比于构造方法set([1, 2, 3])要更快且更易读.后者的速度要慢一些,因为Python必须先从set这个名字来查询构造方法,
然后新建一个列表,最后再把这个列表传入到构造方法里.但是如果是像{1, 2, 3}这样的字面量,Python会利用一个专门的叫做BUILD_SET的字节码来创建集合.

由于Python里没有针对frozenset的特殊字面量句法,我们只能采用构造方法.Python3里frozenset的标准字符串表示形式看起来就像构造方法调用一样.
"""
f1 = frozenset(range(10))
print(f1)  # frozenset({0, 1, 2, 3, 4, 5, 6, 7, 8, 9})


# ------------------------------------集合推导------------------------------------
"""
1.从unicodedata模块里导入name函数,用以获取字符的名字.
2.把编码在32-255之间的字符的名字里有'SIGN'单词的挑出来,放到一个集合里.
"""
from unicodedata import name
name1 = {chr(i) for i in range(32, 256) if 'SIGN' in name(chr(i), '')}
print(name1)

# ------------------------------------集合的操作------------------------------------
"""
中缀运算符需要两侧的被操作对象都是集合类型,但是其他的所有方法则只要所传入的参数四可迭代对象.
例如,想求4个聚合类型a,b,c,d的合集,可以用a.union(b, c, d),这里a必须是个set,但是b,c,d则可以是任何类型的可迭代对象.
"""
s1 = {1, 2, 3, 4}
s2 = {3, 4, 5, 6}
l3 = [3, 4, 5, 6]
print(s1.union(s2, l3))  # {1, 2, 3, 4, 5, 6}
"""
集合的数学运算: 这些方法或者会生成新集合,或者会在条件允许的情况下就地修改集合
"""
# S ∩ Z  交集
print(s1 & s2)  # s1.__add__(s2)
print(s2 & s1)  # s1.__rand__(s2)
print(s1.intersection(s2))

s1 &= s2  # s1.__iand__(s2)   就地更新
print(s1)
s1.intersection_update(s2)  # 等同s1 &= s2


# S ∪ Z  并集
print(s1 | s2)  # s1.__or__(s2)
print(s2 | s1)  # s1.__oro__(s2)
print(s1.union(s2))

s1 |= s2  # s1.__ior__(s2)  就地更新
s1.update(s2)  # 就地更新


# S \ Z 差集
print(s1 - s2)  # s1.__sub__(s2)
print(s2 - s1)  # s1.__rsub__(s2)
print(s1.difference(s2))

s1 -= s2  # s1.__isub__(s2)   就地更新
s1.difference_update(s2)  # 就地更新


# S ▲ Z 对称差集
print(s1 ^ s2)  # s1.__xor__(s2)
print(s2 ^ s1)  # s1.__rxor__(s2)
print(s1.symmetric_difference(s2))

s1 ^= s2  # s1.__ixor__(s2)  就地更新
s1.symmetric_difference_update(s2)  # 就地更新

"""
集合的比较运算符,返回值是布尔类型
"""
s1.isdisjoint(s2)   # 查看s1和s2是否不相交(没有共同元素)

# e ∈ s1
e = 1
print(e in s1)  # s1.__contains__(e)

# S1 ⊆ S2
print(s1 <= s2)  # s1.__le__(s2)
s1.issubset(s2)  # 把可迭代对象转化为集合,然后查看s1是否是它的子集

# S1 ⊊ S2
print(s1 < s2)  # s1.__lt__(s2)

# S1是否S2的父集
print(s1 >= s2)  # s1.__ge__(s2)
s1.issuperset(s2)  # 可以使用可迭代对象

# S1是否S2的真父集
print(s1 > s2)  # s1.__gt__(s2)

"""
集合类型的其他方法
"""
s1.add(7)
s1.clear()
s3 = s1.copy()
s1.discard(1)  # 如果s1中有1这个元素的话,把它移除
s1.pop()  # 从s1中移除一个元素并返回它的值,若s1为空,抛出KeyError异常
s1.remove(1)  # 从s1中移除1,若1不存在,抛出KeyError异常
s1.__iter__()  # 返回s1的迭代器
s1.__len__()  # len(s1)
posted @ 2020-06-20 10:17  怀心抱素  阅读(227)  评论(0编辑  收藏  举报