August Rush

一个还在努力成长的小火汁!

游龙当归海,海不迎我自来也。

We create our own demons.

You can reach me at augustrush0923@gmail.com
Python的collections模块
发布:2021年06月03日 | 作者:augustrush | 阅读量: 680

collections模块

在内置数据类型(dict、list、set、tuple)的基础上,collections模块还提供了几个额外的数据类型:Counter、deque、defaultdict、namedtuple和OrderedDict等。

  1. namedtuple: 生成可以使用名字来访问元素内容的tuple

  2. deque: 双端队列,可以快速的从另外一侧追加和推出对象

  3. Counter: 计数器,主要用来计数

  4. OrderedDict: 有序字典

  5. defaultdict: 带有默认值的字典


namedtuple

tuple表示不变集合,例如:一个点的二维坐标

p = (1, 2)

但是,看到(1,2)很难看出这个tuple是用来表示一个坐标的。

这时,namedtuple就派上了用场:

from collections import namedtuple

Point = namedtuple('Point', ['x', 'y'])

p = Point(1, 2)

print(p.x, p.y)
# 1, 2

namedtuple的定义:

# namedtuple('名称', [属性list])
Circle = namedtuple('Circle', ['x', 'y', 'r'])

流畅的python(Fluent Python)中,其作者Luciano Ramalhonamedtuple徒手实现了一副扑克牌

from collections import namedtuple

Cards = namedtuple('Card', ['rank', 'suit'])


class FrenchDeck:
    ranks = [n for n in range(2, 11)] + list('JQKA')
    suit = 'spades diamonds clubs hearts'.split()
    def __init__(self):
        self._card = [Cards(rank, suit) for rank in ranks for suit in suits]

    def __len__(self):
        return len(self._card)

    def __getitem__(self, position):
        return self._card[position]


deque

使用list存储数据时,按索引访问元素很快,但是插入和删除元素就很慢了,因为list是线性存储,数据量大的时候,插入和删除效率很低。

deque是为了高效实现插入和删除操作的双向列表,适合用于队列和栈:

from collections import deque

q = deque(['a', 'b', 'c'])
q.append('x')
q.appendleft('y')

print(q)
# deque(['y', 'a', 'b', 'c', 'x'])

deque除了实现list的append()pop()操作外,还支持appendleft()popleft(),这样就可以非常高效地往头部添加或删除元素。


OrderedDict

使用dict时,Key是无序的。(在python 3.7+版本中dict默认保持插入顺序)。在对dict做迭代时,我们无法确定key的顺序。

如果需要保持key的顺序,可以用OrderedDict:

from collections import OrderedDict

d = dict([('a',1), ('b',2), ('c',3)])
print(d)
# {'a': 1, 'c': 3, 'b': 2} # python 3.7之前

od = OrderedDict([('a',1), ('b',2), ('c',3)])
print(od)
# OrderedDict([('a', 1), ('b', 2), ('c', 3)])

OrderedDict的key是按照插入的顺序排列,不是key本身排序。

在Python 3.7+中,大多数情况下,普通的 dict 能够替换 collections.OrderedDict


defaultdict

使用dict时,如果引用不存在的key,就会抛出KeyError。如果希望key不存在时,返回一个默认值,就可以用defaultdict:

from collections import defaultdict

dd = defaultdict(lambda: 'N/A')

dd['key1'] = 'value1'

print(dd['key1'])
# 'value1'
print(dd['key2'])
# 'N/A'

defaultdict默认值必须是一个可调用对象或None

想象有如下场景,有一集合 [11,22,33,44,55,66,77,88,99,90...]。需求是将大于60的值保存至字典的第一个key中,将小于60的值保存至第二个key的值中。

原生字典解决方案:

li = [11, 22, 33, 44, 55, 66, 77, 88, 99, 90]
dic = {}
for l in li:
    if l > 60:
        if dic.has_key('k1'):
            dic['k1'].append(l)
        else:
            dic['k1'] = [l]
    if l < 60:
        if dic.has_key('k2'):
            dic['k2'].append(l)
        else:
            dic['k2'] = [l]

defaultdict字典解决方案:

from collections import defaultdict

li = [11, 22, 33, 44, 55, 66, 77, 88, 99, 90]
dd = defaultdict(list)

for l in li:
    if l > 60:
        dd['k1'].append(l)
    if l < 60:
        dd['k2'].append(l)


Counter

Counter类的目的是用来跟踪值出现的次数。它是一个无序的容器类型,以字典的键值对形式存储,其中元素作为key,其计数作为value。计数值可以是任意的Interger(包括0和负数)。

c = Counter('abcdeabcdabcaba')
print(c)
# Counter({'a': 5, 'b': 4, 'c': 3, 'd': 2, 'e': 1})


创建

Counter 创建的四种方法:

c1 = Counter()  # 创建一个空的Counter类
c2 = Counter('gallahad')  # 从一个可iterable对象(list、tuple、dict、字符串等)创建
c3 = Counter({'a':4, 'b':2})  # 从一个字典对象创建
c4 = Counter(a=4, b=2)  # 从一组键值对创建


计数值的访问与缺失的键

当所访问的键不存在时,返回0,而不是KeyError;否则返回它的计数。

c = Counter("abcdefgab")

print(c["a"])
# 2
print(c["c"])
# 1
print(c["h"])
# 0


计数器的更新

可以使用一个iterable对象或者另一个Counter对象来更新键值。

计数器的更新包括增加和减少两种。其中,增加使用update()方法:

c = Counter('which')
print(c['h'])  # 2

c.update('witch')  # 使用另一个iterable对象更新
print(c['h'])  # 3

d = Counter('watch')
c.update(d)  # 使用另一个Counter对象更新
print(c['h'])  # 4

减少则使用subtract()方法:

c = Counter('which')
c.subtract('witch')  # 使用另一个iterable对象更新
print(c['h'])  # 1

d = Counter('watch')
c.substact(d)  # 使用另一个Counter对象更新
print(c['a'])  # -1


键的修改和删除

当计数值为0时,并不意味着元素被删除,删除元素应当使用del

c = Counter("abcdcba")
print(c)
# Counter({'a': 2, 'c': 2, 'b': 2, 'd': 1})

c["b"] = 0
print(c)
# Counter({'a': 2, 'c': 2, 'd': 1, 'b': 0})

del c["a"]
print(c)
# Counter({'c': 2, 'b': 2, 'd': 1})


elements()

返回一个迭代器。元素被重复了多少次,在该迭代器中就包含多少个该元素。元素排列无确定顺序,个数小于1的元素不被包含。

c = Counter(a=4, b=2, c=0, d=-2)

print(list(c.elements()))
# ['a', 'a', 'a', 'a', 'b', 'b']


most_common([n])

返回一个TopN列表。如果n没有被指定,则返回所有元素。当多个元素计数值相同时,排列是无确定顺序的。

c = Counter('abracadabra')

print(c.most_common())
# [('a', 5), ('r', 2), ('b', 2), ('c', 1), ('d', 1)]

print(c.most_common(3))
# [('a', 5), ('r', 2), ('b', 2)] 


浅拷贝

>>> c = Counter("abcdcba")
>>> c
Counter({'a': 2, 'c': 2, 'b': 2, 'd': 1})
>>> d = c.copy()
>>> d
Counter({'a': 2, 'c': 2, 'b': 2, 'd': 1})


算术和集合操作

+、-、&、|操作也可以用于Counter。其中&和|操作分别返回两个Counter对象各元素的最小值和最大值。需要注意的是,得到的Counter对象将删除小于1的元素。

>>> c = Counter(a=3, b=1)
>>> d = Counter(a=1, b=2)
>>> c + d  # c[x] + d[x]
Counter({'a': 4, 'b': 3})
>>> c - d  # subtract(只保留正数计数的元素)
Counter({'a': 2})
>>> c & d  # 交集:  min(c[x], d[x])
Counter({'a': 1, 'b': 1})
>>> c | d  # 并集:  max(c[x], d[x])
Counter({'a': 3, 'b': 2})


其他常用操作

下面是一些Counter类的常用操作,来源于Python官方文档

sum(c.values())  # 所有计数的总数
c.clear()  # 重置Counter对象,注意不是删除
list(c)  # 将c中的键转为列表
set(c)  # 将c中的键转为set
dict(c)  # 将c中的键值对转为字典
c.items()  # 转为(elem, cnt)格式的列表
Counter(dict(list_of_pairs))  # 从(elem, cnt)格式的列表转换为Counter类对象
c.most_common()[:-n:-1]  # 取出计数最少的n个元素
c += Counter()  # 移除0和负值


  • 标签云

  • 支付宝扫码支持一下

  • 微信扫码支持一下



基于Nginx+Supervisord+uWSGI+Django1.11.1+Python3.6.5构建

京ICP备20007446号-1 & 豫公网安备 41100202000460号

网站地图 & RSS | Feed