python中sort和sorted的高级排序技巧

2023-05-16

Python list内置sort()方法用来排序,也可以用python内置的全局sorted()方法来对可迭代的序列排序生成新的序列。

1.排序基础

简单的升序排序是非常容易的。只需要调用sorted()方法。它返回一个新的list,新的list的元素基于小于运算符(__lt__)来排序。
代码如下:

>>> sorted([5, 2, 3, 1, 4])
[1, 2, 3, 4, 5]

你也可以使用list.sort()方法来排序,此时list本身将被修改。通常此方法不如sorted()方便,但是如果你不需要保留原来的list,此方法将更有效。

代码如下:

>>> a = [5, 2, 3, 1, 4]
>>> a.sort()
>>> a
[1, 2, 3, 4, 5]

另一个不同就是list.sort()方法仅被定义在list中,相反地sorted()方法对所有的可迭代序列都有效。
复制代码 代码如下:

>>>
sorted({1: 'D', 2: 'B', 3: 'B', 4: 'E', 5: 'A'})
[1, 2, 3, 4, 5]

2.key参数/函数

从python2.4开始,list.sort()和sorted()函数增加了key参数来指定一个函数,此函数将在每个元素比较前被调用。 例如通过key指定的函数来忽略字符串的大小写:
复制代码 代码如下:

>>> sorted("This is a test string from Andrew".split(), key=str.lower)
['a', 'Andrew', 'from', 'is', 'string', 'test', 'This']

key参数的值为一个函数,此函数只有一个参数且返回一个值用来进行比较。这个技术是快速的因为key指定的函数将准确地对每个元素调用。

更广泛的使用情况是用复杂对象的某些值来对复杂对象的序列排序,例如:

代码如下:

>>> student_tuples = [
        ('john', 'A', 15),
        ('jane', 'B', 12),
        ('dave', 'B', 10),
]
>>> sorted(student_tuples, key=lambda student: student[2])   # sort by age
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]

同样的技术对拥有命名属性的复杂对象也适用,例如:

代码如下:

>>> class Student:
        def __init__(self, name, grade, age):
                self.name = name
                self.grade = grade
                self.age = age
        def __repr__(self):
                return repr((self.name, self.grade, self.age))
>>> student_objects = [
        Student('john', 'A', 15),
        Student('jane', 'B', 12),
        Student('dave', 'B', 10),
]
>>> sorted(student_objects, key=lambda student: student.age)   # sort by age
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]

3.Operator 模块函数

上面的key参数的使用非常广泛,因此python提供了一些方便的函数来使得访问方法更加容易和快速。operator模块有itemgetter,attrgetter,从2.6开始还增加了methodcaller方法。使用这些方法,上面的操作将变得更加简洁和快速:

代码如下:

>>> from operator import itemgetter, attrgetter
>>> sorted(student_tuples, key=itemgetter(2))
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
>>> sorted(student_objects, key=attrgetter('age'))
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]

operator模块还允许多级的排序,例如,先以grade,然后再以age来排序:

代码如下:

>>> sorted(student_tuples, key=itemgetter(1,2))
[('john', 'A', 15), ('dave', 'B', 10), ('jane', 'B', 12)]
>>> sorted(student_objects, key=attrgetter('grade', 'age'))
[('john', 'A', 15), ('dave', 'B', 10), ('jane', 'B', 12)]

4.升序和降序

list.sort()和sorted()都接受一个参数reverse(True or False)来表示升序或降序排序。

例如对上面的student降序排序如下:

代码如下:

>>> sorted(student_tuples, key=itemgetter(2), reverse=True)
[('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]
>>> sorted(student_objects, key=attrgetter('age'), reverse=True)
[('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]

 

5.排序的稳定性和复杂排序

从python2.2开始,排序被保证为稳定的。意思是说多个元素如果有相同的key,则排序前后他们的先后顺序不变。

代码如下:

>>> data = [('red', 1), ('blue', 1), ('red', 2), ('blue', 2)]
>>> sorted(data, key=itemgetter(0))
[('blue', 1), ('blue', 2), ('red', 1), ('red', 2)]

注意在排序后’blue’的顺序被保持了,即’blue’, 1在’blue’, 2的前面。

更复杂地你可以构建多个步骤来进行更复杂的排序,例如对student数据先以grade降序排列,然后再以age升序排列。

代码如下:

>>> s = sorted(student_objects, key=attrgetter('age'))     # sort on secondary key
>>> sorted(s, key=attrgetter('grade'), reverse=True)       # now sort on primary key, descending
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]

6.最老土的排序方法-DSU

我们称其为DSU(Decorate-Sort-Undecorate),原因为排序的过程需要下列三步:
第一:对原始的list进行装饰,使得新list的值可以用来控制排序;
第二:对装饰后的list排序;
第三:将装饰删除,将排序后的装饰list重新构建为原来类型的list;

例如,使用DSU方法来对student数据根据grade排序:

>>> decorated = [(student.grade, i, student) for i, student in enumerate(student_objects)]
>>> decorated.sort()
>>> [student for grade, i, student in decorated]               # undecorate
[('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]

上面的比较能够工作,原因是tuples是可以用来比较,tuples间的比较首先比较tuples的第一个元素,如果第一个相同再比较第二个元素,以此类推。

并不是所有的情况下都需要在以上的tuples中包含索引,但是包含索引可以有以下好处:
第一:排序是稳定的,如果两个元素有相同的key,则他们的原始先后顺序保持不变;
第二:原始的元素不必用来做比较,因为tuples的第一和第二元素用来比较已经是足够了。

此方法被RandalL.在perl中广泛推广后,他的另一个名字为也被称为Schwartzian transform。

对大的list或list的元素计算起来太过复杂的情况下,在python2.4前,DSU很可能是最快的排序方法。但是在2.4之后,上面解释的key函数提供了类似的功能。

7.其他语言普遍使用的排序方法-cmp函数

在python2.4前,sorted()和list.sort()函数没有提供key参数,但是提供了cmp参数来让用户指定比较函数。此方法在其他语言中也普遍存在。

在python3.0中,cmp参数被彻底的移除了,从而简化和统一语言,减少了高级比较和__cmp__方法的冲突。

在python2.x中cmp参数指定的函数用来进行元素间的比较。此函数需要2个参数,然后返回负数表示小于,0表示等于,正数表示大于。例如:

代码如下:

>>> def numeric_compare(x, y):
        return x - y
>>> sorted([5, 2, 4, 1, 3], cmp=numeric_compare)
[1, 2, 3, 4, 5]

或者你可以反序排序:

代码如下:

>>> def reverse_numeric(x, y):
        return y - x
>>> sorted([5, 2, 4, 1, 3], cmp=reverse_numeric)
[5, 4, 3, 2, 1]

当我们将现有的2.x的代码移植到3.x时,需要将cmp函数转化为key函数,以下的wrapper很有帮助:

代码如下:

#Python小白学习交流群:711312441
def cmp_to_key(mycmp):
    'Convert a cmp= function into a key= function'
    class K(object):
        def __init__(self, obj, *args):
            self.obj = obj
        def __lt__(self, other):
            return mycmp(self.obj, other.obj) < 0
        def __gt__(self, other):
            return mycmp(self.obj, other.obj) > 0
        def __eq__(self, other):
            return mycmp(self.obj, other.obj) == 0
        def __le__(self, other):
            return mycmp(self.obj, other.obj) <= 0
        def __ge__(self, other):
            return mycmp(self.obj, other.obj) >= 0
        def __ne__(self, other):
            return mycmp(self.obj, other.obj) != 0
    return K

当需要将cmp转化为key时,只需要:

代码如下:

>>> sorted([5, 2, 4, 1, 3], key=cmp_to_key(reverse_numeric))
[5, 4, 3, 2, 1]

从python2.7,cmp_to_key()函数被增加到了functools模块中。

8.其他注意事项

  • 对需要进行区域相关的排序时,可以使用locale.strxfrm()作为key函数,或者使用local.strcoll()作为cmp函数。
  • reverse参数任然保持了排序的稳定性,有趣的时,同样的效果可以使用reversed()函数两次来实现:
    复制代码 代码如下:
>>> data = [('red', 1), ('blue', 1), ('red', 2), ('blue', 2)]
>>> assert sorted(data, reverse=True) == list(reversed(sorted(reversed(data))))
  • 其实排序在内部是调用元素的__cmp__来进行的,所以我们可以为元素类型增加__cmp__方法使得元素可比较,例如:
    代码如下:
>>> Student.__lt__ = lambda self, other: self.age < other.age
>>> sorted(student_objects)
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
  • key函数不仅可以访问需要排序元素的内部数据,还可以访问外部的资源,例如,如果学生的成绩是存储在dictionary中的,则可以使用此dictionary来对学生名字的list排序,如下:
    复制代码 代码如下:
>>> students = ['dave', 'john', 'jane']
>>> newgrades = {'john': 'F', 'jane':'A', 'dave': 'C'}
>>> sorted(students, key=newgrades.__getitem__)
['jane', 'dave', 'john']
  • 当你需要在处理数据的同时进行排序的话,sort(),sorted()或bisect.insort()不是最好的方法。在这种情况下,可以使用heap,red-black tree或treap。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

python中sort和sorted的高级排序技巧 的相关文章

  • 列出类的所有实例

    我编写了一个 Python 模块 其中有几个类继承自一个名为MasterBlock 我想在脚本中导入此模块 创建这些类的多个实例 然后获取该类的所有子级的所有现有实例的列表MasterBlock班级 我找到了一些解决方案vars Block
  • “NoneType”对象不可订阅?

    list1 name1 info1 10 list2 name2 info2 30 list3 name3 info3 50 MASTERLIST list1 list2 list3 def printer lst print Availa
  • Pytorch 损失为 nan

    我正在尝试用 pytorch 编写我的第一个神经网络 不幸的是 当我想要得到损失时遇到了问题 出现以下错误信息 RuntimeError Function LogSoftmaxBackward0 returned nan values in
  • 如何在cvxpy中编写多个约束?

    我想在 cvxpy 下的优化问题中添加许多约束 在 matlab 中 我可以通过添加一行 subject to 然后使用 for 循环来生成约束 我怎样才能在 cvxpy 中做同样的工作 因为 cvxpy 中没有 服从 概念 有什么建议吗
  • Django/gevent socket.IO 与 redis pubsub。我把东西放在哪里?

    我有一个独立的 python 脚本 它只是从 Twitter 的流 API 捕获数据 然后在收到每条消息时 使用 redis pubsub 将其发布到频道 tweets 这是该脚本 def main username username pa
  • 映射器无法组装任何主键列

    我从 sqlite 表创建了一个临时表 该表是基于各种选择标准的原始表的子集 屏幕截图中有一个示例 我试图一次循环一个表记录 以便更新每个记录中的字段 我有 source table self source engine create en
  • 将图像转换为二进制流

    我的应用程序有两个方面 一方面我使用 C 来使用 Pleora 的 EBUS SDK 从相机读取帧 当第一次接收到该流时 在将缓冲区转换为图像之前 我能够一次读取 16 位流 以便对每个像素执行一些计算 即每个像素都存在一个 16 位数据块
  • python中remove方法的安全使用

    我从列表继承了一个 UserList 类并实现了以下方法来删除标记为已删除的条目 def purge deleted self for element in list iter self if ele mark deleted lt 1 s
  • Python 中 Goto 标签的替代方案?

    我知道我不能使用 Goto 我也知道 Goto 不是答案 我读过类似的问题 但我只是想不出解决我的问题的方法 所以 我正在编写一个程序 你必须在其中猜测一个数字 这是我遇到问题的部分的摘录 x random randint 0 100 I
  • Emacs:调试Python的方法

    我把这个贴在程序员 stackexchange com https softwareengineering stackexchange com questions 29844 emacs methods for debugging pyth
  • 为什么在 python 控制台中对 SparkSession.builder.getOrCreate() 的调用被视为命令行 Spark-submit?

    代替python console我正在尝试创建一个Spark Session 我没有使用pyspark以隔离依赖关系 为什么是spark submit命令行提示并生成错误 NOTE SPARK PREPEND CLASSES is set
  • 在 Python 中将 int 转换为 ASCII 并返回

    我正在为我的网站制作一个 URL 缩短器 我当前的计划 我愿意接受建议 是使用节点 ID 来生成缩短的 URL 因此 理论上 节点 26 可能是short com z 节点 1 可能是short com a 节点 52 可能是short c
  • 使用 pythons strftime 显示日期,例如“5 月 5 日”? [复制]

    这个问题在这里已经有答案了 可能的重复 Python 日期顺序输出 https stackoverflow com questions 739241 python date ordinal output 在Python中 time strf
  • 没有名为 urllib.parse 的模块(我应该如何安装它?)

    我正在尝试在 CentOS 7 上运行 REST API 我读到 urllib parse is in Python 3 但我使用的是 Python 2 7 5 所以我不知道如何安装此模块 我安装了所有要求 但仍然无法运行该项目 当我寻找
  • NumPy 数组不可 JSON 序列化

    创建 NumPy 数组并将其保存为 Django 上下文变量后 加载网页时收到以下错误 array 0 239 479 717 952 1192 1432 1667 dtype int64 is not JSON serializable
  • 使用 PIL 合并图像时模式不匹配

    我正在传递 jpg 文件的名称 def split image into bands filename img Image open filename data img getdata red d 0 0 0 for d in data L
  • 使用 PuLP 进行线性优化,变量附加条件

    我必须用 Pull 解决 Python 中的整数线性优化问题 我解决了基本问题 现在我必须添加额外的约束 有人可以帮助我用逻辑指示器添加条件吗 逻辑限制是 如果 A gt 20 则 B gt 5 这是我的代码 from pulp impor
  • 继承自 NumPy 数组的类如何更改其自身的值?

    我有一个继承自 NumPy n 维数组的简单类 我想要该类的两个方法可以更改该类实例的数组值 其中一种方法应将类实例的数组设置为类实例的列表数据属性的值 另一种方法应将一些列表值附加到类实例的数组中 我不确定如何实现这一点 但我的尝试如下
  • 每行中最后一次出现 True 的索引

    我有一个二维数组 a False False False False False True True True True True True True True True True True True True True True True
  • 张量流多元线性回归不收敛

    我正在尝试使用张量流训练具有正则化的多元线性回归模型 由于某种原因 我无法获取以下代码的训练部分来计算我想要用于梯度下降更新的误差 我在设置图表时做错了什么吗 def normalize data matrix averages np av

随机推荐

  • DHCP snooping

    一 采用DHCP服务的常见问题 架设DHCP服务器可以为客户端自动分配IP地址 掩码 默认网关 DNS服务器等网络参数 xff0c 简化了网络配置 xff0c 提高了管理效率 但在DHCP服务的管理上存在一些问题 xff0c 常见的有 xf
  • 组播技术架构

    组播基础 span class hljs attribute 1 保留的组播地址 224 0 0 1 224 0 0 255 公网上的组播地址 224 0 1 0 238 255 255 255 私网上的组播地址 239 0 0 0 239
  • python中的三元运算符

    python中没有类似java或c 43 43 中的 三元运算符 xff0c 如果想用类似的结构 xff0c 可以用if else来代替 x span class token operator 61 span span class toke
  • 关于派生类构造函数与基类构造函数的调用顺序问题

    面向对象程序设计基础 xff08 第二版 李师贤等 xff0c 第254页 xff1a C 43 43 语言的基本规则是 xff1a 创建一个派生类的对象时 xff0c 如果基类带有构造函数 xff0c 则先调用基类的构造函数 xff0c
  • C++中的strrev函数

    C 43 43 中的strrev函数 C 43 43 中有函数strrev xff0c 功能是对字符串实现反转 xff0c 但是要记住 xff0c strrev函数只对字符数组有效 xff0c 对string类型是无效的 具体见下面代码 x
  • 工厂模式(Factory Pattern)

    Java工厂模式 xff08 Factory Pattern xff09 是一种创建型设计模式 xff0c 它提供了一个通用的接口来创建对象 xff0c 但允许子类决定实例化哪个类 这种模式通过将对象的创建委托给工厂类来实现 xff0c 从
  • Java建造者模式(Builder Pattern)

    ava建造者模式 xff08 Builder Pattern xff09 是一种创建型设计模式 xff0c 它将对象的构建过程分离出来 xff0c 使得可以使用相同的构建过程来创建不同的对象表示形式 建造者模式通常用于创建复杂的对象 xff
  • Can‘t uninstall ‘scipy‘. No files were found to uninstall.以及scipy安装问题解决方法

    ubuntu系统下使用pip uninstall scipy命令卸载包时 遇到报错信息为 Found existing installation span class token operator span scipy span class
  • Package ‘libssl1.0.0‘ has no installation candidate

    安装libssl1 0 0失败 xff0c 问题 xff1a Package libssl1 0 0 has no installation candidate 解决方法 xff1a sudo apt get install build e
  • IDR 学习笔记

    Multiview Neural Surface Reconstruction by Disentangling Geometry and Appearance 主页 xff1a https lioryariv github io idr
  • Debian 11 驱动问题解决方法

    Debian 11 驱动问题解决方法 前言问题解决方法升级内核安装 Firmware Linux 前言 下面是作者在安装时的系统版本和无法驱动的硬件信息 xff1a Debian 镜像 xff1a debian 11 6 0 amd64 D
  • 使用windows引导的ubuntu双操作系统

    避坑指南 bios 取消安全boot 安全启动 快速启动 报rst错误的 把 bois 里的 SATA config 把inter 改为ahci 没报请无视 作为码农 xff0c 总会时不时的需要使用linux的开发环境 xff0c 使用虚
  • 想听一首歌好难?程序员教你一键下载

    1 首先要先安装一下Python第三方库 requests pip install requestsprettytable pip install PrettyTable 2 使用的开发环境 xff1a 版 本 xff1a python 3
  • 圣诞要到了~教你用Python制作一个表白神器——照片墙,祝你成功

    马上圣诞节 xff0c 快到了 xff01 又到了一年一度表白的时候了 今天教你一个程序员方式的表白 xff01 看一下效果图 xff1a 要什么样的 xff0c 图案都可以自定义的 首先 xff0c 准备阶段 收集你喜欢人 xff08 或
  • python字典遍历

    对python中的字典进行遍历操作 a span class token operator 61 span span class token punctuation span span class token punctuation spa
  • python读取文件指定行的三种方法

    1 行遍历实现 在python中如果要将一个文件完全加载到内存中 xff0c 通过file readlines 即可 xff0c 但是在文件占用较高时 xff0c 我们是无法完整的将文件加载到内存中的 xff0c 这时候就需要用到pytho
  • Python中五种方式拼接字符串的正确方法

    在学习Python xff08 3x xff09 的过程中 xff0c 在拼接字符串的时候遇到了些问题 xff0c 所以抽点时间整理一下Python 拼接字符串的几种方式 方式1 使用加号 43 连接 使用加号连接各个变量或者元素必须是字符
  • Python类与对象详解

    一 类和对象 类的意思 xff1a 种类 分类 类别 对象是特征与技能的结合体 xff0c 我可能有身高体重 而你也有身高体重 xff0c 所以你会说你像我 xff0c 但是你一定不会说你像阿猫阿狗 并且我和你其实就可以说成是一类 xff0
  • Python如何连接Mysql及基本操作

    1 什么要做python连接mysql xff0c 一般是解决什么问题的 做自动化测试时候 xff0c 注册了一个新用户 xff0c 产生了多余的数据 xff0c 下次同一个账号就无法注册了 xff0c 这种情况怎么办呢 xff1f 自动化
  • python中sort和sorted的高级排序技巧

    Python list内置sort 方法用来排序 xff0c 也可以用python内置的全局sorted 方法来对可迭代的序列排序生成新的序列 1 排序基础 简单的升序排序是非常容易的 只需要调用sorted 方法 它返回一个新的list