前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >python:collections模块中的数据结构

python:collections模块中的数据结构

作者头像
生信菜鸟团
发布2022-01-05 14:00:13
5190
发布2022-01-05 14:00:13
举报
文章被收录于专栏:生信菜鸟团

python中的数据结构除了内置的数据结构如列表、字典、元组、集合等之外,python的colletions内置模块中还有一些高级的数据结构,可以在特定场景下提高便利性,缩减代码量。colletions中的常用数据结果有:

Counter:自动计数

Counter可以对传入的可迭代对象进行元素计数,返回一个字典,键为元素,值为元素的数量。

代码语言:javascript
复制
import collections
## init
c1 = collections.Counter([1, 2, 3, 4, 3, 2, 1, 2, 2])
c2 = collections.Counter("abscdadaeda")
c3 = collections.Counter({'a': 1, 'b':3})
#>>> c1;c2;c3
#Counter({2: 4, 1: 2, 3: 2, 4: 1})
#Counter({'a': 4, 'd': 3, 'b': 1, 's': 1, 'c': 1, 'e': 1})
#Counter({'b': 3, 'a': 1})

## update,用于更新计数的结果;substract类似,用于从计数结果中减去结果
c1.update({'5': 10})
#>>> c1
#Counter({'5': 10, 2: 4, 1: 2, 3: 2, 4: 1})

## most_common,用于输出最多的几个结果
#>>> c2.most_common(2)
#[('a', 4), ('d', 3)]

## elements:返回经过Counter计算后的所有元素的结果,返回一个迭代器
#>>> c3;list(c3.elements())
#Counter({'b': 3, 'a': 1})
#['a', 'b', 'b', 'b']

deque:双向队列

两端均可操作元素的一个队列,它支持的操作有:

  • 左右两端添加元素:append appendleft
  • 左右两端更新元素集(列表、字典、元组):extend extendleft
  • 左右两端删除元素并返回此元素值:pop popleft
  • 计数count;反转reverse;清空clear;移除remove等操作

如果控制只在一端操作就是Stack或者Queue。可以稍微封装一下可操作的函数来变为一个Stack或Queue,以Stack为例:

代码语言:javascript
复制
class stack(collections.deque):
    def __init__(self, *args, **kwargs):
        collections.deque.__init__(self, *args, **kwargs)

    def appendleft(self, *args, **kwargs):
        raise Exception("Stack have no operation: appendleft")

    def extendleft(self, *args, **kwargs):
        raise ForbiddenOperationException(obj="Stack", operation="extendleft")

    def popleft(self):
        raise ForbiddenOperationException(obj="Stack", operation="popleft")

# test
s = stack()
s.append(1)
s.append(2)
#>>> s
#stack([1, 2])

s.appendleft(3)
#>>> s.appendleft(3)
#  File "<stdin>", line 1, in <module>
#  File "<stdin>", line 6, in appendleft
#Exception: Stack have no operation: appendleft

s.pop() # 2, 后进先出
s.popleft()
#>>> s.popleft()
#Traceback (most recent call last):
#  File "<stdin>", line 1, in <module>
#  File "<stdin>", line 12, in popleft
#Exception: Stack have no operation: popleft

defaultdict

默认字典,继承自字典,可以使用字典的全部方法,只不过在索引值的时候,如果键不存在会返回一个定义的默认值。

代码语言:javascript
复制
## 字典无相应的值会报错
d = {}
d['a']
#Traceback (most recent call last):
#  File "<stdin>", line 1, in <module>
#KeyError: 'a'

# 当然get方法是可以指定默认值,但是它和默认字典的使用场景并不相同
d.get('a', "default value")

## 默认字典
d1 = collections.defaultdict(int)
d1['a'] # 0,而不是报错

## 如果是多层字典,可以使用lambda
# {'A':{'a':1}, 'B':{'b':1}}
d2 = collections.defaultdict(lambda: collections.defaultdict(int))
d2['A']['a'] = 1
d2['A']['a'] # 1
d2

## 默认字典在计数中的应用
# 如果是相对复杂的情况,无法直接使用Counter的情况下,需要手动进行循环计数,下面是手动计数的例子
def countUseDict(obj):
    if not isinstance(obj, collections.abc.Sequence):
        # 指定只使用序列对象
        raise Exception("Only iterable object supported.")
    res = {}
    ####计数####
    for o in obj:
        if not o in res.keys():
            res[o] = 0
        res[o] += 1
    return res

def countUseDefaultdict(obj):
    if not isinstance(obj, collections.abc.Sequence):
        raise Exception("Only iterable object supported.")
    res = collections.defaultdict(int)
    ####计数####
    for o in obj: res[o] += 1
    return dict(res)


countUseDict("askdfnasnf") == countUseDefaultdict("askdfnasnf")
# True
countUseDict([1, 2, 3, 4, 4, 7, 5, 5, 6]) == countUseDefaultdict([1, 2, 3, 4, 4, 7, 5, 5, 6])
# True

OrderedDict

python中的字典是无序的,也就是创建的字典元素的顺序不保证是稳定的且和创建顺序一样。

字典的无序是指,不能人为重新排序。 比如说你按键值1,2,3,4的顺序创建的字典,只能由解析器按创建顺序,还是1,2,3,4的输出。 你无法控制它按照4,3,2,1的顺序输出,你也无法做到1,3,2,4的顺序。 而且这个输出顺序是也不是能真正按照创建顺序可以控的。 这里面有两个影响因素: (1)键值的哈希碰撞,hash(key1) == hash(key2)时,向字典里连续添加的这个两个键的顺序是不可以控制的,也是无法做到连续的,后来的键会按算法调整到其它位置。 (2)字典空间扩容,当键的数量超过字典默认开的空间时,字典会做空间扩容,扩容后的键顺和创建顺序就会发生变化,不受人为控制。 (https://www.cnblogs.com/yibeimingyue/p/9977164.html)

代码语言:javascript
复制
#定义有序字典  
dic2 = OrderedDict()  
dic2['a'] = '123'  
dic2['b'] = 'jjj'  
dic2['c'] = 'abc'  
dic2['d'] = '999'  
#>>> dic2
#OrderedDict([('a', '123'), ('b', 'jjj'), ('c', 'abc'), ('d', '999')])

namedtuple

命名元组,类似于R中的list(list拥有names属性),元组的每个元素对应一个名字,使用这个名字可以取值。

代码语言:javascript
复制
## 定义一个命名元组,返回一个构造函数
Student = collections.namedtuple('Student', ['Name', 'Age', 'Sex'])

stu1 = Student("LL", "21", "Male")
stu2 = Student("HMM", "21", "Female")
stu1.Name # 'LL'
stu2.Age # '21'

## 命名规则需要服从python的变量命名规则,否则会报错
student = collections.namedtuple("student", ["name", "age", "class"])
#Traceback (most recent call last):
#  File "<stdin>", line 1, in <module>
#  File "D:\Anaconda3\lib\collections\__init__.py", line 361, in namedtuple
#    raise ValueError('Type names and field names cannot be a '
#ValueError: Type names and field names cannot be a keyword: 'class'

# 如果命名冲突可以让python自动更名:下划线加位置
student = collections.namedtuple("student", ["name", "age", "class"], rename = True)
s1 = student("LL", 21, "class 1")
#>>> s1
#student(name='LL', age=21, _2='class 1')
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-12-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 生信菜鸟团 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Counter:自动计数
  • deque:双向队列
  • defaultdict
  • OrderedDict
  • namedtuple
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档