zoukankan      html  css  js  c++  java
  • Python序列结构--集合

    集合:元素之间不允许重复

    • 集合属于Python无序可变序列,元素之间不允许重复

    集合对象的创建与删除

    • 直接将值赋值给变量即可创建一个集合

      >>> a = {3,5}
      >>> type(a)
      <class 'set'>
    • set()函数将列表、元组、字符串、range对象等其他可迭代对象转换为集合,如果原来的数据中存在重复元素,则转换为集合的时候只保留一个;如果原序列或迭代对象中有不可哈希的值,无法转换为集合,抛出异常

      >>> a_set=set(range(8,14))
      >>> a_set
      {8, 9, 10, 11, 12, 13}
      >>> b_set = set([0,1,2,3,0,1,2,3,7,8])
      >>> b_set
      {0, 1, 2, 3, 7, 8}
    • 集合推导式来快速生成集合

      >>> {x.strip() for x in ('he ','she  ','  I')}
      {'I', 'he', 'she'}
      >>> import random
      >>> x = {random.randint(1,500) for i in range(100)} #生成随机数,自动去除重复的元素
      >>> len(x) # 一般而言输出结果会小于100
      94
      >>> {str(x) for x in range(10)}
      {'1', '9', '4', '8', '3', '7', '2', '6', '0', '5'}

    集合的操作与运算

    集合元素的增加和删除
    • add()方法可以增加新元素,如果该元素已存在则忽略该操作,不会抛出异常;update()方法合并另外一个集合中的元素到当前集合中,并且自动去除重复元素

      >>> s = {1,2,3}
      >>> s.add(3) # 添加元素,重复元素自动忽略
      >>> s.update({3,4}) # 更新字典,自动忽略重复的元素
      >>> s
      {1, 2, 3, 4}
    • pop()方法随机删除并返回集合中的一个元素,如果为空则抛出异常;remove()方法删除集合中的元素,如果指定元素不存在则抛出异常;discard()方法从集合中删除一个特定的元素,如果元素不存在则忽略该操作;clear()方法清空集合

      >>> s
      {1, 2, 3, 4}
      >>> s.discard(5) # 删除元素,不存在则忽略该操作
      >>> s.remove(5) # 删除元素,不存在则抛出异常
      Traceback (most recent call last):
       File "<stdin>", line 1, in <module>
      KeyError: 5
      >>> s.pop() # 删除并返回元素
      1
      >>> s
      {2, 3, 4}
      >>> s.clear()
      >>> s
      set()
    集合运算
    • 内置函数len()、max()、min()、sum()、sorted()、map()、filter()、enumerate()等也适用于集合。另外还支持数学意义上的交集、并集、差集等运算

      >>> a_set = set([8,9,10,11,12,113])
      >>> a_set
      {8, 9, 10, 11, 12, 113}
      >>> b_set = {0,1,2,3,7,8}
      >>> a_set | b_set # 并集
      {0, 1, 2, 3, 7, 8, 9, 10, 11, 12, 113}
      >>> a_set.union(b_set) # 并集
      {0, 1, 2, 3, 7, 8, 9, 10, 11, 12, 113}
      >>> a_set & b_set # 交集
      {8}
      >>> a_set.intersection(b_set)
      {8}
      >>> a_set.difference(b_set) # 差集
      {9, 10, 11, 12, 113}
      >>> b_set.difference(a_set)
      {0, 1, 2, 3, 7}
      >>> a_set - b_set
      {9, 10, 11, 12, 113}
      >>> b_set - a_set
      {0, 1, 2, 3, 7}
      >>> a_set.symmetric_difference(b_set) # 对称差集
      {0, 1, 2, 3, 7, 9, 10, 11, 12, 113}
      >>> a_set ^ b_set
      {0, 1, 2, 3, 7, 9, 10, 11, 12, 113}
      >>> x = {1,2,3}
      >>> y = {1,2,5}
      >>> z = {1,2,3,4}
      >>> x < y # 比较集合大小/包含关系
      False
      >>> x < z # 真子集True>>> y < zFalse>>> z < zFalse>>> z <= z # 子集True>>> x.issubset(y) # 测试是否为子集False>>> x.issubset(z)True>>> x.issubset(x)True

    不可变集合frozenset

    用法与set基本类似,与set类不同的是,frozenset是不可变集合,没有提供add()、remove()等可以修改集合对象的方法
    
    >>> x = frozenset(range(5))
    >>> x
    frozenset({0, 1, 2, 3, 4})
    >>> x.add(2)
    Traceback (most recent call last):
     File "<stdin>", line 1, in <module>
    AttributeError: 'frozenset' object has no attribute 'add'
    >>> x | frozenset(range(5,10)) # 并集
    frozenset({0, 1, 2, 3, 4, 5, 6, 7, 8, 9})
    >>> x & frozenset(range(4,10)) # 交集
    frozenset({4})
    >>> x - frozenset(range(4,10)) # 差集
    frozenset({0, 1, 2, 3})
    >>> frozenset(range(4)) < frozenset(range(5)) # 集合包含关系比较
    True

    集合应用案例

    • python字典和集合都使用hash表来存储元素,元素查询速度快,关键字in作用于字典和集合比作用于列表要快得多

      >>> import random
      >>> x1 = list(range(10000))
      >>> x2 = tuple(range(10000))
      >>> x3 = set(range(10000))
      >>> x4 = dict(zip(range(10000),range(10000)))
      >>> r = random.randint(0,9999)
      >>> for t in (x4, x3, x2, x1):
      ...   start = time.time()
      ...   for i in range(9999999):
      ...     flag = (r in t)
      ...   print(type(t),'time used:', time.time() - start)
      ...
      <class 'dict'> time used: 0.865715503692627
      <class 'set'> time used: 0.9040701389312744
      <class 'tuple'> time used: 487.52976393699646
      <class 'list'> time used: 488.0697581768036
    • 作为集合快速的具体应用,可以使用集合快速提取序列中单一元素,即提取序列中所有不重复的元素

      >>> import random
      >>> listRandom = [random.choice(range(1000)) for i in range(100)]
      >>> len(listRandom)
      100
      >>> newSet = set(listRandom)
      >>> len(newSet)
      95
    • 返回指定范围内一定数量的不重复数字

      >>> import random
      >>> def randomNumbers(number,start,end):
      ...   '''使用集合生成number个介于start和end之间的不重复随机数'''
      ...   data = set()
      ...   while len(data) < number:
      ...     element = random.randint(start,end)
      ...     data.add(element)
      ...   return data
      ...
      >>> randomNumbers(10,1,1000)
      {66, 676, 550, 522, 333, 783, 499, 278, 59, 349}
    • 返回指定范围内一定数量的不重复数字,使用random模块的sample()函数更好一些,但是random模块的sample()函数只支持列表、元组、集合、字符串和range对象,不支持字典以及map、zip、enumerate、filter等惰性求值的迭代对象

      >>> import random
      >>> random.sample(range(1, 700), 10) # 选取指定分布中选取不重复元素
      [340, 489, 623, 121, 550, 632, 19, 531, 626, 591]
    • 下面两段代码用来测试指定列表中是否包含非法数据,很明显第二段用集合的代码效率高一些

      >>> import random
      >>> lstColor = ('red','green','blue')
      >>> colors = [random.choice(lstColor) for i in range(10000)]
      >>> for item in colors:
      ...   if item not in lstColor:
      ...     print('error:',item)
      ...     break
      ...
      >>>
      >>> if (set(colors) - set(lstColor)):
      ...   print('error')
      ...
      >>>
    • 使用字典和集合模拟有向图结构,并实现了节点的入度和出度计算

      >>> def getDegress(orientedGraph,node):
      ...   outDegree = len(orientedGraph.get(node,[]))
      ...   inDegree = sum(1 for v in orientedGraph.values() if node in v)
      ...   return (inDegree, outDegree)
      ...
      >>> graph = {'a' : set('bcdef'), 'b':set('ce'), 'c':set('d'), 'd': set('e'), 'e':set('f'), 'f':set('cgh'),'g':set('fhi'), 'h':set('fgi'), 'i':set() }
      >>> print(getDegress(graph, 'h'))
      (2, 3)
      >>>

    序列解包的多种形式和用法

    序列解包是Python中非常重要和常用的一个功能,可以使用非常简洁的形式完成复杂的功能,提高代码的可读性,减少了程序员代码的输入量
    
    >>> x,y,z = 1,2,3
    >>> x
    1
    >>> y
    2
    >>> z
    3
    >>> v_tuple = (False,3.5,'exp')
    >>> (x,y,z) = v_tuple
    >>> m,n,q = v_tuple
    >>> m,n,q = range(2)
    Traceback (most recent call last):
     File "<stdin>", line 1, in <module>
    ValueError: not enough values to unpack (expected 3, got 2)
    >>> m,n,q = range(3) # 对range对象进行序列解包
    >>> x,y,z = range(4)
    Traceback (most recent call last):
     File "<stdin>", line 1, in <module>
    ValueError: too many values to unpack (expected 3)
    >>> x,y,z = iter([1,2,3]) # 使用迭代器对象进行序列解包
    >>> x,y,z = map(str,range(3)) # 使用可迭代的map对象进行序列解包
    >>> x
    '0'
    >>> y
    '1'
    >>> x,y =y,x # 交换两个变量的值
    >>> x
    '1'
    >>> y
    '0'
    序列解包还可用于列表、字典、enumerate对象、filter对象等,对字典使用时,默认是对字典“键”进行操作,如果对“键:值“对进行操作应使用字典的items()方法说明,如果需要对字典”值“进行操作应该使用字典的values()方法明确指定
    
    >>> a = [1,2,3]
    >>> b,c,d = a
    >>> x,y,z = sorted([1,3,2])
    >>> s = {'a':1,'b':2,'c':3}
    >>> b,c,d = s.items()
    >>> b
    ('a', 1)
    >>> c
    ('b', 2)
    >>> d
    ('c', 3)
    >>> b,c,d = s
    >>> b
    'a'
    >>> c
    'b'
    >>> d
    'c'
    >>> b,c,d = s.values()
    >>> b
    1
    >>> c
    2
    >>> d
    3
    >>> a,b,c='ABC'
    >>> a
    'A'
    >>> b
    'B'
    >>> c
    'C'
    使用序列解包可以很方便地同时遍历多个序列
    
    >>> keys = ['a','b','c','d']
    >>> values = [1,2,3,4]
    >>> for k,v in zip(keys,values):
    ...   print((k,v),end=' ')
    ...
    ('a', 1) ('b', 2) ('c', 3) ('d', 4) >>>
    >>> x = ['a','b','c']
    >>> for i,v in enumerate(x):
    ...   print('The value on position {0} is {1}'.format(i,v))
    ...
    The value on position 0 is a
    The value on position 1 is b
    The value on position 2 is c
    >>> s = {'a':1,'b':2,'c':3}
    >>> for k,v in s.items():
    ...   print((k,v),end=' ')
    ...
    ('a', 1) ('b', 2) ('c', 3) >>>
    序列解包的另类用法和错误的用法:
    
    >>> print(*[1,2,3])
    1 2 3
    >>> print(*[1,2,3],4,*(5,6))
    1 2 3 4 5 6
    >>> *range(4),4
    (0, 1, 2, 3, 4)
    >>> *range(4)
     File "<stdin>", line 1
    SyntaxError: can't use starred expression here
    >>> {*range(4),4,*(5,6,7)}
    {0, 1, 2, 3, 4, 5, 6, 7}
    >>> {'x':1,**{'y':2}}
    {'x': 1, 'y': 2}
    >>> a,b,c,d = range(3),3
    Traceback (most recent call last):
     File "<stdin>", line 1, in <module>
    ValueError: not enough values to unpack (expected 4, got 2)
    >>> a,b,c,d = *range(3),3
    下面的代码看起来与序列解包类型,但严格来说是序列解包的逆运算,与函数的可变长度参数一样,用来接收等号右侧的多个数值
    
    >>> a,*b,c = 1,2,3,4,5
    >>> a
    1
    >>> b
    [2, 3, 4]
    >>> c
    5
    >>> a,b,c
    (1, [2, 3, 4], 5)
    >>> a,*b,c = range(20)
    >>> b
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]
    >>> *b = 1,2,4 # 等号左边必须为列表、元组或多个变量
     File "<stdin>", line 1
    SyntaxError: starred assignment target must be in a list or tuple
  • 相关阅读:
    hdu 2137
    hdu 2059
    hdu 2175
    hdu 1297
    hdu 1702
    hdu 1212
    hdu 1397
    [转]常见的碱性食品有哪些?
    [转]C#反射
    每个人都有自己的未来
  • 原文地址:https://www.cnblogs.com/zxbdboke/p/10480215.html
Copyright © 2011-2022 走看看