0%

Python colletions模块详细介绍

一、模块详细介绍

collections 包含了一些特殊的容器,针对Python内置的容器,例如:list、dict、set和tuple,提供了另外一种选择

namedtuple:可以创建包含名称的tuple;
deque:类似于list的容器,可以快速的在队列头部和尾部添加、删除元素;
Counter,dict的子类,计算可hash的对象;
OrderedDict,dict的子类,可以记住元素的添加顺序;
defaultdict,dict的子类,可以调用提供默认值的函数;

二、模块使用

  1. Counter

    counter可以支持方便,快速的计数。例如

    1
    2
    3
    4
    5
    6
    7
    from collections import *

    cnt = Counter()
    wordList = ["a","b","c","c","a","a"]
    for word in wordList:
    cnt[word] += 1
    print cnt

​ 控制台输出

1
Counter({'a': 3, 'c': 2, 'b': 1})
   对可迭代的对象进行计数或者从另一个映射进行初始化
1
2
3
4
5
6
7
8
9
10
11
12
>>> c = Counter()#一个新的,空的counter
>>> c
Counter()
>>> c = Counter("gallahad")#从可迭代的字符串初始化counter
>>> c
Counter({'a': 3, 'l': 2, 'h': 1, 'g': 1, 'd': 1})
>>> c = Counter({'red':4,'blue':2})#从映射初始化counter
>>> c
Counter({'red': 4, 'blue': 2})
>>> c = Counter(cats = 4,dogs = 8)#从args初始化counter
>>> c
Counter({'dogs': 8, 'cats': 4})

​ Counter 对象类似于字典,如果某个项缺失,会返回0,而不是报出KeyError

1
2
3
4
5
>>> c = Counter(['eggs','ham'])
>>> c['bacon']#没有'bacon'
0
>>> c['eggs']#有'eggs'
1

​ 将一个元素的数目设置为0,并不能把它从counter中删除,使用del可以将这个元素删除;

1
2
3
4
5
>>> c = Counter(['eggs','ham'])
>>> c['bacon']#没有'bacon'
0
>>> c['eggs']#有'eggs'
1

​ Counter对象支持以下三个字典不支持的方法,elements(), most_common(), subtract();
​ elements()返回一个迭代器,每个元素重复的次数为它的数目,顺序是任意的顺序,如果一个元素的数目少于1,那么elements()就会忽略它;

1
2
3
4
5
>>> c = Counter(a=2,b=4,c=0,d=-2,e = 1)
>>> c
Counter({'b': 4, 'a': 2, 'e': 1, 'c': 0, 'd': -2})
>>> list(c.elements())
['a', 'a', 'b', 'b', 'b', 'b', 'e']

most_common 返回一个列表,包含counter中n个最大数目的元素,如果忽略n或者为None,most_common()将会返回counter中的所有元素,元素有着相同数目的将会以任意顺序排列;

1
2
3
4
5
6
>>> Counter('abracadabra').most_common(3)
[('a', 5), ('r', 2), ('b', 2)]
>>> Counter('abracadabra').most_common()
[('a', 5), ('r', 2), ('b', 2), ('c', 1), ('d', 1)]
>>> Counter('abracadabra').most_common(None)
[('a', 5), ('r', 2), ('b', 2), ('c', 1), ('d', 1)]

subtract(), 从一个可迭代对象中或者另一个映射(或counter)中,元素相减,类似于dict.update(),但是subtracts 数目而不是替换它们,输入和输出都有可能为0或者为负;

1
2
3
4
5
>> c = Counter(a=4,b=2,c=0,d=-2)
>>> d = Counter(a=1,b=2,c=-3,d=4)
>>> c.subtract(d)
>>> c
Counter({'a': 3, 'c': 3, 'b': 0, 'd': -6})

update, 从一个可迭代对象中或者另一个映射(或counter)中所有元素相加,类似于dict.upodate,是数目相加而非替换它们,另外,可迭代对象是一个元素序列,而非(key,value)对构成的序列;

1
2
3
4
5
6
7
>>> c
Counter({'a': 4, 'b': 2, 'c': 0, 'd': -2})
>>> d
Counter({'d': 4, 'b': 2, 'a': 1, 'c': -3})
>>> c.update(d)
>>> c
Counter({'a': 5, 'b': 4, 'd': 2, 'c': -3})

​ Counter对象常见的操作,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
>>> c
Counter({'a': 5, 'b': 4, 'd': 2, 'c': -3})
>>> sum(c.values())# 统计所有的数目
8
>>> list(c)# 列出所有唯一的元素
['a', 'c', 'b', 'd']
>>> set(c)# 转换为set
set(['a', 'c', 'b', 'd'])
>>> dict(c)# 转换为常规的dict
{'a': 5, 'c': -3, 'b': 4, 'd': 2}
>>> c.items()# 转换为(elem,cnt)对构成的列表
[('a', 5), ('c', -3), ('b', 4), ('d', 2)]
>>> c.most_common()[:-4:-1]# 输出n个数目最小元素
[('c', -3), ('d', 2), ('b', 4)]
>>> c += Counter()# 删除数目为0和为负的元素
>>> c
Counter({'a': 5, 'b': 4, 'd': 2})
>>> Counter(dict(c.items()))# 从(elem,cnt)对构成的列表转换为counter
Counter({'a': 5, 'b': 4, 'd': 2})
>>> c.clear()# 清空counter
>>> c
Counter()

​ 在Counter对象进行数学操作,得多集合(counter中元素数目大于0)加法和减法操作,是相加或者相减对应元素的数目;交集和并集返回对应数目的最小值和最大值;每个操作均接受暑促是有符号的数目,但是输出并不包含数目为0或者为负的元素;

1
2
3
4
5
6
7
8
9
10
>>> c = Counter(a=3,b=1,c=-2)
>>> d = Counter(a=1,b=2,c=4)
>>> c+d#求和
Counter({'a': 4, 'b': 3, 'c': 2})
>>> c-d#求差
Counter({'a': 2})
>>> c & d#求交集
Counter({'a': 1, 'b': 1})
>>> c | d#求并集
Counter({'c': 4, 'a': 3, 'b': 2})
  1. deque

    deque是栈和队列的一种广义实现,deque是”double-end queue”的简称;deque支持线程安全、有效内存地以近似O(1)的性能在deque的两端插入和删除元素,尽管list也支持相似的操作,但是它主要在固定长度操作上的优化,从而在pop(0)和insert(0,v)(会改变数据的位置和大小)上有O(n)的时间复杂度。

    deque支持如下方法,

    append(x), 将x添加到deque的右侧;

    appendleft(x), 将x添加到deque的左侧;

    clear(), 将deque中的元素全部删除,最后长度为0;

    count(x), 返回deque中元素等于x的个数;

    extend(iterable), 将可迭代变量iterable中的元素添加至deque的右侧;

    extendleft(iterable), 将变量iterable中的元素添加至deque的左侧,往左侧添加序列的顺序与可迭代变量iterable中的元素相反;

    pop(), 移除和返回deque中最右侧的元素,如果没有元素,将会报出IndexError;

    popleft(), 移除和返回deque中最左侧的元素,如果没有元素,将会报出IndexError;

    remove(value), 移除第一次出现的value,如果没有找到,报出ValueError;

    reverse(), 反转deque中的元素,并返回None;

    rotate(n), 从右侧反转n步,如果n为负数,则从左侧反转,d.rotate(1)等于d.appendleft(d.pop());

    maxlen, 只读的属性,deque的最大长度,如果无解,就返回None;

    除了以上的方法之外,deque还支持迭代、序列化、len(d)、reversed(d)、copy.copy(d)、copy.deepcopy(d),通过in操作符进行成员测试和下标索引,索引的时间复杂度是在两端是O(1),在中间是O(n),为了快速获取,可以使用list代替

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    >>> from collections import deque
    >>> d = deque('ghi')# 新建一个deque,有三个元素
    >>> for ele in d:# 遍历deque
    ... print ele.upper()
    ...
    ...
    G
    H
    I
    >>> d.append('j')# deque右侧添加一个元素
    >>> d.appendleft('f')# deque左侧添加一个元素
    >>> d# 打印deque
    deque(['f', 'g', 'h', 'i', 'j'])
    >>> d.pop()# 返回和移除最右侧元素
    'j'
    >>> d.popleft()# 返回和移除最左侧元素
    'f'
    >>> list(d)# 以列表形式展示出deque的内容
    ['g', 'h', 'i']
    >>> d[0]# 获取最左侧的元素
    'g'
    >>> d[-1]# 获取最右侧的元素
    'i'
    >>> list(reversed(d))# 以列表形式展示出倒序的deque的内容
    ['i', 'h', 'g']
    >>> 'h' in d# 在deque中搜索
    True
    >>> d.extend('jkl')# 一次添加多个元素
    >>> d
    deque(['g', 'h', 'i', 'j', 'k', 'l'])
    >>> d.rotate(1)# 往右侧翻转
    >>> d
    deque(['l', 'g', 'h', 'i', 'j', 'k'])
    >>> d.rotate(-1)# 往左侧翻转
    >>> d
    deque(['g', 'h', 'i', 'j', 'k', 'l'])
    >>> deque(reversed(d))# 以逆序新建一个deque
    deque(['l', 'k', 'j', 'i', 'h', 'g'])
    >>> d.clear()# 清空deque
    >>> d.pop()# 不能在空的deque上pop
    Traceback (most recent call last):
    File "<input>", line 1, in <module>
    IndexError: pop from an empty deque
    >>> d.extendleft('abc')# 以输入的逆序向左扩展
    >>> d
    deque(['c', 'b', 'a'])

    其他的应用

    1. 限定长度的deque提供了Unix中tail命令相似的功能

      1
      2
      3
      4
      5
      6
      7
      from collections import deque

      def tail(filename,n = 10):
      "Return the last n lines of a file"
      return deque(open(filename),n)

      print tail("temp.txt",10)
    2. 使用deque维护一个序列(右侧添加元素,左侧删除元素)中窗口的平均值;

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      from collections import deque
      import itertools

      def moving_average(iterable,n = 3):
      it = iter(iterable)
      d = deque(itertools.islice(it,n-1))
      # 第一次只有两个元素,再右移的过程中,需要先删除最左端的元素,因此现在最左端加入0
      d.appendleft(0)
      s = sum(d)
      for ele in it:
      # 删除最左端的元素,再加上新元素
      s += ele - d.popleft()
      # 右端添加新元素
      d.append(ele)
      yield s / float(n)

      array = [40,30,50,46,39,44]
      for ele in moving_average(array,n=3):
      print ele
    3. rotate()方法提供了一种实现deque切片和删除的方式,例如,del d[n]依赖于rotate方法的纯Python实现,如下,

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      from collections import deque

      def delete_nth(d,n):
      # 将前n个元素翻转到右侧
      d.rotate(-n)
      # 删除第n个元素
      d.popleft()
      # 再将后n个元素翻转到左侧
      d.rotate(n)

      d = deque("abcdefg")
      delete_nth(d,n = 3)
      print d
    4. slice依赖于rotate方法的纯Python实现,如下

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      from collections import deque

      def slice(d,m,n):
      # 先将前面m个元素翻转到右侧
      d.rotate(-m)
      i = m
      sliceList = []
      # 依次将[m,n]区间内的元素出栈
      while i < n:
      item = d.popleft()
      sliceList.append(item)
      i+=1
      # 再将出栈的元素扩展到deque右侧
      d.extend(sliceList)
      # 再将后面n个元素翻转到左侧
      d.rotate(n)
      return sliceList

      d = deque("abcdefg")
      print slice(d,1,5)
-------------Thanks for your attention-------------