我的编程空间,编程开发者的网络收藏夹
学习永远不晚

以SortedList为例详解Python的defaultdict对象使用自定义类型的方法

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

以SortedList为例详解Python的defaultdict对象使用自定义类型的方法

写在前面

最近写周赛题, 逃不开的一种题型是设计数据结构, 也就是第三题, 做这种题需要的就是对语言中的容器以及常用排序查找算法的掌握, 而我只熟悉了最基本的一些方法, 做起这些题来总是超时…

为了搞定这些题, 我决定学习一下大佬们的做法, 特别是优先队列的方法维护有序容器以及有序列表等容器, 这些都在Python中封装好了, 用起来很是方便, 但是采用defaultdict的时候, 其缺省数据类型常常需要与题目给出的特定结构匹配, 这就需要定义一个新的数据类型, 下面我就以一种十分常用的结构SortedList为例, 设置自定义的数据类型(本例为将默认的升序列表变成降序列表).

其他的数据结构当然也可以根据下面列出的方法来改, 主要知识点就是函数与类的运用了

第一种方法: 封装成函数

首先导入需要的函数, 其中neg方法可以用lambda x: -x代替, 本质上是一样的, 下面写的代码这两种均可.

from collections import defaultdict
from sortedcontainers import (SortedList as SL, SortedKeyList as SKL)
from operator import neg  # or `lambda x: -x`

然后我们来看第一种方法, 其实封装成函数本质上就是将自定义对象作为函数返回值, 下面给出两种实现, 其实不传入参数也可以, 但是这样的话下面的第15行就不能使用了, 只能通过add()来添加值, 还是有局限的.

代码中的d2直接用一个新的lambda函数, 定义键, 就不需要考虑直接初始化失效的情况.

def reverseSL(x=None):
    return SL(iterable=x, key=lambda x: -x)

def reverseSL1_no_args():
    return SL(key=lambda x: -x)

d1 = defaultdict(reverseSL)
d2 = defaultdict(lambda: SL(key=neg))

data = [3, 2, 4, 1]
for i in data:
    d1[1].add(i)
    d2[1].add(i)
# 也可以直接加入排序列表
d1[2] = reverseSL([1, 2])
d2[2] = reverseSL([1, 2])
print(d1)
print(d2)

可以得到如下的结果:

defaultdict(<function reverseSL at 0x100a680d0>, {1: SortedKeyList([4, 3, 2, 1], key=<function reverseSL.<locals>.<lambda> at 0x100c659d0>), 2: SortedKeyList([2, 1], key=<function reverseSL.<locals>.<lambda> at 0x100caa550>)})
defaultdict(<function <lambda> at 0x100c65820>, {1: SortedKeyList([4, 3, 2, 1], key=<built-in function neg>), 2: SortedKeyList([2, 1], key=<function reverseSL.<locals>.<lambda> at 0x100cb9940>)})
[Finished in 214ms]

如果第15行改为:

d1[2] = reverseSL_no_args([1, 2])

就会提示:TypeError: reverseSL_no_args() takes 0 positional arguments but 1 was given, 但是add()方法不会有问题.

第二种方法: 类封装

这种方法比较复杂, 并且有一个小坑, 这里先看第一个类的代码.

我这里实现了两个类, 其中mySL1采用的是组合的面向对象设计方法, mySL2用的是继承. 第一种代码比较多, 因为里面添加了一个组件SortedList, 就需要重写add().

class mySL1:
    def __init__(self, iterable=None):
        self.sl = SL(iterable=iterable, key=lambda x: -x)
    def add(self, item):
        self.sl.add(item)
    def get(self):
        return list(self.sl)
    def __repr__(self):
        return repr(self.sl)

其中的__repr__是可选的, 只是为了清楚地显示已加入到defaultdict的数据情况. 不写的话还得调用get()方法, 进行字典值(values)数据的输出, 这里为方便就直接转换为List类型了, 如果不转换, 没办法在类外通过list()进行转换, 因为这样得到的数据不是可迭代对象, 通过直接输出值的类型, 可以得到<class '__main__.mySL1'>.

然后是第二个类, 继承语法简洁明了, 直接调用父类的初始化方法, 但是这里需要注意的是, 继承SortedList类的代码这里就不能用了, 因为如果还是使用SortedList, 在__init__中修改key就会提示断言错误, assert key is None, 这个问题让我比较困惑, 甚至觉得可能继承的方法行不通,(下面是模块的__new__方法的源码) 我知道了问题的所在.

    def __new__(cls, iterable=None, key=None):
        """Create new sorted list or sorted-key list instance.
        Optional `key`-function argument will return an instance of subtype
        :class:`SortedKeyList`.
        >>> sl = SortedList()
        >>> isinstance(sl, SortedList)
        True
        >>> sl = SortedList(key=lambda x: -x)
        >>> isinstance(sl, SortedList)
        True
        >>> isinstance(sl, SortedKeyList)
        True
        :param iterable: initial values (optional)
        :param key: function used to extract comparison key (optional)
        :return: sorted list or sorted-key list instance
        """
        # pylint: disable=unused-argument
        if key is None:
            return object.__new__(cls)
        else:
            if cls is SortedList:
                return object.__new__(SortedKeyList)
            else:
                raise TypeError('inherit SortedKeyList for key argument')

这里模块的作者提供了一个SortedList的子类, 叫做SortedKeyList, 顾名思义, 就是提供了一种可以写入key的类, 这时候继承这个类就不会有问题了.

其实在上面的函数调用那块, 就已经有所提示, 输出结果中的类型, 就显示是SortedKeyList, 这个类型就是修改了key(使得key is not None)之后得到的对象. 大家可以尝试一下, 如果不修改key, 就还是SortedList.

class mySL2(SKL):
    """use SortedKeyList instead SortedList,
    because SortedList cannot init argument `key`,
    `assert key is None` in its `__init__`"""

    def __init__(self, iterable=None):
        super().__init__(iterable=iterable, key=neg)

最后是创建defaultdict, 以及数据的读取:

d3 = defaultdict(mySL1)
d4 = defaultdict(mySL2)
for i in [19, 11, 12, 123]:
    d3['x'].add(i)
    d4['y'].add(i)
# 或者直接通过列表初始化
d3['z'] = mySL1([1, 2])
d4['w'] = mySL2([1, 2])
print(d3)
print(d4)
print(d3['x'].get(), d3['z'].get())
print(list(d4['y']), list(d4['w']))

可以得到下面的结果:

defaultdict(<class '__main__.mySL1'>, {'x': SortedKeyList([123, 19, 12, 11], key=<function mySL1.__init__.<locals>.<lambda> at 0x1008e40d0>), 'z': SortedKeyList([2, 1], key=<function mySL1.__init__.<locals>.<lambda> at 0x100bebd30>)})
defaultdict(<class '__main__.mySL2'>, {'y': mySL2([123, 19, 12, 11], key=<built-in function neg>), 'w': mySL2([2, 1], key=<built-in function neg>)})
[123, 19, 12, 11] [2, 1]
[123, 19, 12, 11] [2, 1]

可以看出, 第一种类的创建, 其实最后还是用到了SortedKeyList这个子类.

到此这篇关于以SortedList为例详解Python的defaultdict对象使用自定义类型的方法的文章就介绍到这了,更多相关Python defaultdict内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

以SortedList为例详解Python的defaultdict对象使用自定义类型的方法

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

vue props使用typescript自定义类型的方法实例

这篇文章主要给大家介绍了关于vue props使用typescript自定义类型的相关资料,文中通过实例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
2023-01-28

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录