1. 字典排序

我们知道 Python 的内置 dictionary 数据类型是无序的,通过 key 来获取对应的 value。可是有时我们需要对 dictionary 中的 item 进行排序输出,可能根据 key,也可能根据 value 来排。到底有多少种方法可以实现对 dictionary 的内容进行排序输出呢?下面摘取了使用 sorted 函数实现对 dictionary 的内容进行排序输出一些精彩的解决办法。

1.1 按 key 值对字典排序

先基本介绍一下 sorted 函数,sorted(iterable,key,reverse)sorted 一共有 iterablekeyreverse 这三个参数。

  • 其中 iterable 表示可以迭代的对象,例如可以是 dict.items()dict.keys() 等。
  • key 是一个函数,用来选取参与比较的元素。
  • reverse 则是用来指定排序是倒序还是顺序, reverse=true 则是倒序, reverse=false  时则是顺序,默认时 reverse=false

要按 key 值对字典排序,则可以使用如下语句:

In [1]: d = {"lilee":25, "wangyuan":21, "liquan":32, "zhangsan":18, "lisi":28}

In [2]: sorted(d.keys())
Out[2]: ['lilee', 'liquan', 'lisi', 'wangyuan', 'zhangsan']

In [3]: sorted(d)
Out[3]: ['lilee', 'liquan', 'lisi', 'wangyuan', 'zhangsan']

直接使用 sorted(d.keys()) 就能按 key 值对字典排序,这里是按照顺序对 key 值排序的,如果想按照倒序排序的话,则只要将 reverse 置为 true 即可。

1.2 按 value 值对字典排序

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

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

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

  • cmp 参数(python3 中已经被移除,不推荐)
In [3]: sorted(d.items(), lambda x, y: cmp(x[1], y[1]), reverse=True)
Out[3]: 
[('liquan', 32),
 ('lisi', 28),
 ('lilee', 25),
 ('wangyuan', 21),
 ('zhangsan', 18)]
  • key 参数(推荐)
In [4]: sorted(d.items(), key=lambda item:item[1], reverse=True)
Out[4]: 
[('liquan', 32),
 ('lisi', 28),
 ('lilee', 25),
 ('wangyuan', 21),
 ('zhangsan', 18)]
  1. 这里的 d.items()实际上是将 d 转换为可迭代对象,迭代对象的元素为 ('liquan', 32)('lisi', 28)......('zhangsan', 18)
  2. items()方法将字典的元素转化为了元组,而这里 key 参数对应的 lambda 表达式的意思则是选取元组中的第二个元素作为比较参数(如果写作 key=lambda item:item[0] 的话则是选取第一个元素作为比较对象,也就是 key 值作为比较对象。 lambda x:y 中 x 表示输出参数,y 表示 lambda 函数的返回值),所以采用这种方法可以对字典的 value 进行排序。
  3. 注意排序后的返回值是一个 list,而原字典中的名值对被转换为了 list 中的元组。

2. 列表/元组排序

2.1 列表(元组)简单排序

从 Python 2.4 开始, list.sort()sorted() 都添加了一个 key 参数,以指定要在进行比较之前在每个列表元素上调用的函数。

例如,这是一个不区分大小写的字符串比较:

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

2.2 对嵌套列表(元组)进行排序

网上有不少关于 Python 列表的排序,这里整理一下 Python 对嵌套列表(多重列表)排序的一些方法,以作备忘。

Key Functions

The value of the key parameter should be a function that takes a single argument and returns a key to use for sorting purposes. This technique is fast because the key function is called exactly once for each input record.

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))
        def weighted_grade(self):
                return 'CBA'.index(self.grade) / float(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)]

Operator Module Functions

上面显示的键功能模式(key-function patterns)非常普遍,因此 Python 提供了便利功能,使访问器功能更容易,更快捷(make accessor functions easier and faster)。operator module 模块内置了 itemgetterattrgetter 函数,并且从 Python 2.6 开始增加了 methodcaller 函数。

使用这些功能,以上示例变得更加简单和快捷。

>>> from operator import itemgetter, attrgetter, methodcaller

>>> 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 模块还有可以进行多个级别排序的功能。例如,要按年级然后按年龄排序:

>>> 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)]

在下面的示例中,使用了 operator 模块的第三个函数 methodcaller,其中在对每个学生进行排序之前显示了每个学生的加权成绩:

>>> [(student.name, student.weighted_grade()) for student in student_objects]
[('john', 0.13333333333333333), ('jane', 0.08333333333333333), ('dave', 0.1)]

>>> sorted(student_objects, key=methodcaller('weighted_grade'))
[('jane', 'B', 12), ('dave', 'B', 10), ('john', 'A', 15)]

3. 升序和降序

list.sort()sorted() 方法都接受带有布尔值的 reverse 参数。这用于标记降序排序。

例如,要以相反的年龄顺序获取学生数据:

>>> 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)]

4. 排序稳定性和复杂排序

从 Python 2.2 开始,排序已经被保证是稳定的(sorts are guaranteed to be stable)。这意味着当多个记录具有相同的键时,将保留其原始顺序。

>>> 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)。

这个奇妙的属性使您可以通过一系列排序步骤来构建复杂的排序。例如,要按年级降序然后按年龄升序对学生数据进行排序,请先对年龄进行排序,然后再使用年级再次排序:

>>> 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)]

The Timsort algorithm used in Python does multiple sorts efficiently because it can take advantage of any ordering already present in a dataset.

Python 中使用的 Timsort 算法可以高效地执行多种排序,因为它可以利用数据集中已经存在的任何排序。

5. 多重列表(元组)取交集、并集

这是个人实际项目中的遇到的问题,例如,我们要获取某个基因或者序列的覆盖区域(并集),或者重叠区域(交集),通过多重列表(元组)取交集、并集的方法就可以快速解决这一问题。

"""
获取两个区间的交集区域。
每个区间可以用元组 (start, end), 或者列表 [start, end] 的形式表示起始和终止位置。
> set1 = (1, 1347)
> set2 = (100, 416)
> intersection(set1, set2)
[100, 416]
"""
def intersection(interval_1, interval_2):
    start = max(interval_1[0], interval_2[0])
    end = min(interval_1[1], interval_2[1])
    if start < end:
        return [start, end]
    return None

"""
获取一个列表集的覆盖区域。
每个区间可以用元组 (start, end), 或者列表 [start, end] 的形式表示起始和终止位置。
> positions = [(0, 3), (7, 13), (6, 16)]
> get_union_section(positions)
[(0, 3), (6, 16)]
"""
def get_union_section(intervals):
    sorted_by_lower_bound = sorted(intervals, key=lambda tup: tup[0])
    merged = []

    for higher in sorted_by_lower_bound:
        if not merged:
            merged.append(higher)
        else:
            lower = merged[-1]
            # test for intersection between lower and higher:
            # we know via sorting that lower[0] <= higher[0]
            if higher[0] <= lower[1]:
                upper_bound = max(lower[1], higher[1])
                merged[-1] = [lower[0], upper_bound]  # replace by merged interval
            else:
                merged.append(higher)
    return merged

"""
获取两列表集的 overlap 交集区域,。
每个区间可以用元组 (start, end), 或者列表 [start, end] 的形式表示起始和终止位置。
> NM_0311 = [(1, 316), (516, 746), (218, 328)]
> XM_0173 = [(416, 3915), (1, 106), (512, 3915), (18, 116)]
> get_inersection(NM_0311, XM_0173)
[[1, 116], [516, 746]]
"""
def get_inersection(intervals1, intervals2):
    start = 0
    out_list = []
    ins1 = get_union_section(intervals1)
    ins2 = get_union_section(intervals2)
    for interval1 in ins1:
        for j in range(start, len(ins2)):
            inter_section = intersection(interval1, ins2[j])
            if inter_section:
                out_list += [inter_section]
    return out_list

6. 参考资料

[1]

Python Wiki:Sorting Mini-HOW TO

[2]

How to sort a list of lists by a specific index of the inner list?

如何卸载 python setup.py install 安装的包?

2020-05-15

生物信息学 Python 入门之源码安装

2019-09-29

Python 日期和时间函数使用指南

2019-09-21

Python 文件与目录操作方法总结

2019-02-17

六大云端 Jupyter Notebook 平台测评

2019-06-24

本文分享自微信公众号 - 生信科技爱好者(bioitee)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

Python 列表、字典、元组的一些小技巧的更多相关文章

  1. python 列表,字典,元组,字符串,QuerySet之间的相互转换

    1. 列表转换成字典list1 = ['key1','key2','key3']list2 = ['value1','value2'] dict1 = zip(list1,list2) # dict( ...

  2. Python列表、元组、字典和字符串的常用函数

    Python列表.元组.字典和字符串的常用函数 一.列表方法 1.ls.extend(object) 向列表ls中插入object中的每个元素,object可以是字符串,元组和列表(字符串“abc”中 ...

  3. Python对list操作的一些小技巧

    Python对list操作的一些小技巧  由于要搞数学建模,于是从熟悉已久的C++转战Python.虽然才上手,但是Python的语法糖就让我大呼过瘾.不得不说相比于C/C++,Python对于数据的 ...

  4. python列表与元组的用法

    python列表与元组的用法 目录: 列表的用法: 1.增   append   +    extend 2.删  del    remove 3.改   insert 4.查  index 5.反向 ...

  5. python列表(list)的使用技巧及高级操作

    python列表(list)的使用技巧及高级操作置顶 2018年03月25日 13:39:41 顽劣的石头 阅读数:5478 标签: python extend bisect list enumera ...

  6. (转)python 列表与元组的操作简介

    python 列表与元组的操作简介 原文:https://www.cnblogs.com/QG-whz/p/4782809.html 阅读目录 列表 list函数 列表的基本操作 列表方法 元组 tu ...

  7. http://www.yyne.com/python使用-urllib-quote-进行-url-编码小技巧/

    http://www.yyne.com/python使用-urllib-quote-进行-url-编码小技巧/

  8. Python 列表、元组、字典及集合操作详解

    一.列表 列表是Python中最基本的数据结构,是最常用的Python数据类型,列表的数据项不需要具有相同的类型 列表是一种有序的集合,可以随时添加和删除其中的元素 列表的索引从0开始 1.创建列表 ...

  9. Python【列表 字典 元组】

    列表列表用中括号[ ]把各种数据框起来,每一个数据叫作“元素”.每个元素之间都要用英文逗号隔开各种类型的数据(整数/浮点数/字符串)————————————————————————————从列表提取单 ...

  10. Python: 列表,元组,字典的区别

    Python中有3种内建的数据结构:列表,元组和字典 1.列表 list是处理一组有序项目的数据结构,即可以在一个列表中存储一个序列的项目.列表中项目应该包括在方括号中,这样python就知道是在指明 ...

随机推荐

  1. volatile 关键字(轻量级同步机制)

    更多内容,前往IT-BLOG volatile 表示 "不稳定" 的意思.用于修饰共享可变变量,即没有使用 final(不可变变量) 关键字修饰的实例变量或静态变量,相应的变量就被 ...

  2. 在基于vue-next-admin的Vue3+TypeScript前端项目中,为了使用方便全局挂载的对象接口

    在基于vue-next-admin 的 Vue3+TypeScript 前端项目中,可以整合自己的 .NET 后端,前端操作一些功能的时候,为了使用方便全局挂载的对象接口,以便能够快速处理一些特殊的操 ...

  3. aspnetcore中aop的实现

    aaspnetcore开发框架中实现aop不仅仅在业务上,在代码的优雅简洁和架构的稳定上都有着至关重要. 下面介绍三种用过的. 第一种通过System.Reflection的DispatchProxy ...

  4. java多线程基础小白指南--关键字识别(start,run,sleep,wait,join,yield)

    在学习java多线程基础上,会遇到几个关键字,理解并识别它们是掌握多线程的必备知识,下面,我将通过源码或者程序演示给出我对这几个关键字的理解,如果有不同意见,欢迎在评论区或者发私信与我探讨. 一.st ...

  5. Mac 音频转换器推荐 DRmare Audio Converter、Audi Free Auditor

    给大家推荐两款 Mac 上的音频转换器,这两款转换器都可以转换苹果音乐,iTunes歌曲或者一些常规的音轨到MP3, FLAC, WAV, M4A, AAC格式等等,转换后我们就可以在所有的设备和播放 ...

  6. active

    rabbitMQ与activeMQ区别 之前的项目中都用到了这两个消息队列 ActiveMq,传统的消息队列,使用Java语言编写.基于JMS(Java Message Service),采用多线程并 ...

  7. vue之写发表评论思路

    后端接口 var express = require('express'); const sql = require('../sql') const Comment = require('../sql ...

  8. 前端ffmpeg实现视频剪切

    利用ffmpeg实现纯前端视频剪切 注意:在新版本Chrome浏览器中由于安全性问题,只能在https或localhost当中才能正常使用 1. 下载ffmpeg npm install @ffmpe ...

  9. ChatGPT 通识入门

    最近网络上对于Chat GPT的讨论热潮不断地膨胀,一个势必给整个人类社会带来新变革的科技和工具产生了.这个新的工具能够识别自然语言并能够理解上下文的语境,并能够具备人类思维的模型. 但是ChatGP ...

  10. python实现员工信息表

    学习python时,看到的一个题目第一次写博客, 有误的地方还请大佬们指正,十分感谢~要求如下'''文件存储格式如下:id,name,age,phone,job(这行不需要写)1,alice,22,1 ...